Merge "Remove the static physical datasource"
This commit is contained in:
commit
dc48a3ecfa
@ -64,9 +64,6 @@ topics = notifications, vitrage_notifications
|
|||||||
[DEFAULT]
|
[DEFAULT]
|
||||||
notifiers = mistral,nova,webhook
|
notifiers = mistral,nova,webhook
|
||||||
|
|
||||||
[static_physical]
|
|
||||||
changes_interval = 5
|
|
||||||
|
|
||||||
[datasources]
|
[datasources]
|
||||||
snapshots_interval = 120
|
snapshots_interval = 120
|
||||||
EOF
|
EOF
|
||||||
|
@ -37,7 +37,7 @@ VITRAGE_DEPLOY=${VITRAGE_DEPLOY}
|
|||||||
# Toggle for deploying Vitrage with/without nagios
|
# Toggle for deploying Vitrage with/without nagios
|
||||||
VITRAGE_USE_NAGIOS=$(trueorfalse False VITRAGE_USE_NAGIOS)
|
VITRAGE_USE_NAGIOS=$(trueorfalse False VITRAGE_USE_NAGIOS)
|
||||||
|
|
||||||
VITRAGE_DEFAULT_DATASOURCES=${VITRAGE_DEFAULT_DATASOURCES:-nova.host,nova.instance,nova.zone,nagios,static,static_physical,aodh,cinder.volume,neutron.network,neutron.port,heat.stack,doctor,prometheus}
|
VITRAGE_DEFAULT_DATASOURCES=${VITRAGE_DEFAULT_DATASOURCES:-nova.host,nova.instance,nova.zone,nagios,static,aodh,cinder.volume,neutron.network,neutron.port,heat.stack,doctor,prometheus}
|
||||||
|
|
||||||
# for now dont use pip install for the client
|
# for now dont use pip install for the client
|
||||||
LIBS_FROM_GIT=python-vitrageclient
|
LIBS_FROM_GIT=python-vitrageclient
|
||||||
|
@ -24,7 +24,6 @@ Datasources
|
|||||||
|
|
||||||
nagios-config
|
nagios-config
|
||||||
static-config
|
static-config
|
||||||
static-physical-config
|
|
||||||
zabbix_vitrage
|
zabbix_vitrage
|
||||||
k8s_datasource
|
k8s_datasource
|
||||||
|
|
||||||
|
@ -5,14 +5,15 @@ Static Datasource Configuration
|
|||||||
Overview
|
Overview
|
||||||
--------
|
--------
|
||||||
|
|
||||||
The static datasource allows users to integrate the **unmanaged** resources and topology into Vitrage. Unmanaged means
|
The static datasource allows users to integrate **unmanaged** resources and
|
||||||
the resource, relationship or property can not be retrieved from any API or database, except static configuration file.
|
topology into Vitrage. Unmanaged means the resource, relationship or property
|
||||||
|
can not be retrieved from any API or database, except static configuration
|
||||||
|
file. The static configuration may include physical, virtual or application
|
||||||
|
resources.
|
||||||
|
|
||||||
This datasource is static - pre-configured in a file. This is sufficient in many cases where the resources and
|
This datasource is static. It is configured in a file that is being reloaded
|
||||||
relationship is relatively unchanging.
|
periodically, based on the configuration. This is sufficient in many cases
|
||||||
|
where the resources and relationship is relatively unchanging.
|
||||||
Static datasource suppresses the legacy static physical datasource. Theoretically both physical and virtual resources
|
|
||||||
and relationship between them can be configured in it.
|
|
||||||
|
|
||||||
Configure Access to Static
|
Configure Access to Static
|
||||||
--------------------------
|
--------------------------
|
||||||
@ -20,13 +21,13 @@ Configure Access to Static
|
|||||||
The following should be set in **/etc/vitrage/vitrage.conf**, under
|
The following should be set in **/etc/vitrage/vitrage.conf**, under
|
||||||
``[static]`` section:
|
``[static]`` section:
|
||||||
|
|
||||||
+------------------+---------------------------------------------------------+----------------------------------+
|
+------------------+--------------------------------------------------------+----------------------------------+
|
||||||
| Name | Description | Default Value |
|
| Name | Description | Default Value |
|
||||||
+==================+=========================================================+==================================+
|
+==================+========================================================+==================================+
|
||||||
| directory | Directory path from where to load the configurations | /etc/vitrage/static_datasources/ |
|
| directory | Directory path from where to load the configurations | /etc/vitrage/static_datasources/ |
|
||||||
+------------------+---------------------------------------------------------+----------------------------------+
|
+------------------+--------------------------------------------------------+----------------------------------+
|
||||||
| changes_interval | Interval of checking changes in the configuration files | 30 seconds |
|
| changes_interval | Interval of checking changes in the configuration file | 30 seconds |
|
||||||
+------------------+---------------------------------------------------------+----------------------------------+
|
+------------------+--------------------------------------------------------+----------------------------------+
|
||||||
|
|
||||||
Configure Static Mapping
|
Configure Static Mapping
|
||||||
------------------------
|
------------------------
|
||||||
@ -45,11 +46,6 @@ Static datasource use the same semantics as Vitrage template, except for the fol
|
|||||||
There may be more than one configuration file. All files will be read from ``/etc/vitrage/static_datasources/``. See
|
There may be more than one configuration file. All files will be read from ``/etc/vitrage/static_datasources/``. See
|
||||||
previous section on how to configure this location.
|
previous section on how to configure this location.
|
||||||
|
|
||||||
Notes:
|
|
||||||
- Static datasource shares the same configuration folder as legacy static physical datasource.
|
|
||||||
- Both static configuration and legacy static physical configuration will be loaded in Ocata release.
|
|
||||||
- The format is distinguished by checking existence of ``metadata`` key which is only available in static datasource.
|
|
||||||
|
|
||||||
Example
|
Example
|
||||||
+++++++
|
+++++++
|
||||||
|
|
||||||
|
@ -1,98 +0,0 @@
|
|||||||
====================================================
|
|
||||||
DEPRECATED: static physical datasource configuration
|
|
||||||
====================================================
|
|
||||||
|
|
||||||
**The static physical datasource is deprecated and will be removed in Stein
|
|
||||||
release.**
|
|
||||||
|
|
||||||
**Please use the static datasource instead.**
|
|
||||||
|
|
||||||
|
|
||||||
Overview
|
|
||||||
--------
|
|
||||||
|
|
||||||
The Static Physical datasource allows users to integrate the physical topology
|
|
||||||
into Vitrage. Physical topology includes switches and their connection to
|
|
||||||
other switches and physical hosts.
|
|
||||||
|
|
||||||
This datasource is static - pre-configured in a file. This is sufficient in
|
|
||||||
many cases where the physical topology is relatively unchanging.
|
|
||||||
|
|
||||||
Configure Access to Static Physical
|
|
||||||
-----------------------------------
|
|
||||||
|
|
||||||
The following should be set in **/etc/vitrage/vitrage.conf**, under
|
|
||||||
[static_physical] section:
|
|
||||||
|
|
||||||
+------------------+---------------------------------------------------------+----------------------------------+
|
|
||||||
| Name | Description | Default Value |
|
|
||||||
+==================+=========================================================+==================================+
|
|
||||||
| directory | Directory path from where to load the configurations | /etc/vitrage/static_datasources/ |
|
|
||||||
+------------------+---------------------------------------------------------+----------------------------------+
|
|
||||||
| changes_interval | Interval of checking changes in the configuration files | 30 seconds |
|
|
||||||
+------------------+---------------------------------------------------------+----------------------------------+
|
|
||||||
| entities | Static physical entity types list | switch |
|
|
||||||
+------------------+---------------------------------------------------------+----------------------------------+
|
|
||||||
|
|
||||||
|
|
||||||
Configure Static Physical Mapping
|
|
||||||
---------------------------------
|
|
||||||
|
|
||||||
Physical configuration is made for configuring statically physical entities,
|
|
||||||
and their relationships to other entities in the topology.
|
|
||||||
|
|
||||||
Some physical entities, such as switches, can not be retrieved from OpenStack,
|
|
||||||
and so are defined here.
|
|
||||||
|
|
||||||
There may be more than one configuration file. All files will be read from
|
|
||||||
*/etc/vitrage/static_datasources/*. See previous section on how to configure this
|
|
||||||
location.
|
|
||||||
|
|
||||||
Format
|
|
||||||
++++++
|
|
||||||
|
|
||||||
.. code::
|
|
||||||
|
|
||||||
entities:
|
|
||||||
- name: <Physical entity name as appears in configuration>
|
|
||||||
id: <Physical entity id as appears in configuration>
|
|
||||||
type: <Physical entity type - see below for details>
|
|
||||||
state: <default resource state>
|
|
||||||
relationships:
|
|
||||||
- type: <Physical entity type it is connected to - see below for details>
|
|
||||||
name: <Name of physical entity as appears in configuration>
|
|
||||||
id: <Id of physical entity as appears in configuration>
|
|
||||||
relation_type: <Relation name>
|
|
||||||
- type: ...
|
|
||||||
...
|
|
||||||
|
|
||||||
|
|
||||||
Notes:
|
|
||||||
- The "type" key must match the name of a type from an existing datasource.
|
|
||||||
- Type names appear, for each datasource, in its __init__.py file.
|
|
||||||
- For example see */workspace/dev/vitrage/vitrage/datasources/nova/host/__init__.py*
|
|
||||||
|
|
||||||
|
|
||||||
Example
|
|
||||||
+++++++
|
|
||||||
|
|
||||||
The following will define a switch that is attached to host-1 and is a backup
|
|
||||||
of switch-2
|
|
||||||
|
|
||||||
.. code::
|
|
||||||
|
|
||||||
entities:
|
|
||||||
- type: switch
|
|
||||||
name: switch-1
|
|
||||||
id: switch-1 # should be same as name
|
|
||||||
state: available
|
|
||||||
relationships:
|
|
||||||
- type: nova.host
|
|
||||||
name: host-1
|
|
||||||
id: host-1 # should be same as name
|
|
||||||
relation_type: attached
|
|
||||||
- type: switch
|
|
||||||
name: switch-2
|
|
||||||
id: switch-2 # should be same as name
|
|
||||||
relation_type: backup
|
|
||||||
|
|
@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
deprecations:
|
||||||
|
- The static_physical datasource was removed. Please use the static
|
||||||
|
datasource instead.
|
@ -41,9 +41,6 @@ OPTS = [
|
|||||||
min=10,
|
min=10,
|
||||||
help='interval in seconds between checking changes in the'
|
help='interval in seconds between checking changes in the'
|
||||||
'static configuration files'),
|
'static configuration files'),
|
||||||
# NOTE: This folder is already used by static_physical datasource. Legacy
|
|
||||||
# configuration files will NOT be converted automatically. But user will
|
|
||||||
# receive deprecation warnings.
|
|
||||||
cfg.StrOpt('directory', default='/etc/vitrage/static_datasources',
|
cfg.StrOpt('directory', default='/etc/vitrage/static_datasources',
|
||||||
help='static data sources configuration directory')]
|
help='static data sources configuration directory')]
|
||||||
|
|
||||||
|
@ -1,75 +0,0 @@
|
|||||||
# 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.
|
|
||||||
|
|
||||||
|
|
||||||
from oslo_config import cfg
|
|
||||||
from oslo_log import versionutils
|
|
||||||
|
|
||||||
from vitrage.common.constants import DatasourceOpts as DSOpts
|
|
||||||
from vitrage.common.constants import UpdateMethod
|
|
||||||
from vitrage.common import utils
|
|
||||||
|
|
||||||
STATIC_PHYSICAL_DATASOURCE = 'static_physical'
|
|
||||||
SWITCH = 'switch'
|
|
||||||
|
|
||||||
_DEPRECATED_MSG = utils.fmt("""
|
|
||||||
`Static_physical` was deprecated in Queens and and will be removed in Stein.
|
|
||||||
Please use static Datasource.
|
|
||||||
""")
|
|
||||||
|
|
||||||
OPTS = [
|
|
||||||
cfg.StrOpt(DSOpts.TRANSFORMER,
|
|
||||||
default='vitrage.datasources.static_physical.transformer.'
|
|
||||||
'StaticPhysicalTransformer',
|
|
||||||
help='Static physical transformer class path',
|
|
||||||
deprecated_for_removal=True,
|
|
||||||
deprecated_reason=_DEPRECATED_MSG,
|
|
||||||
deprecated_since=versionutils.deprecated.QUEENS,
|
|
||||||
required=True),
|
|
||||||
cfg.StrOpt(DSOpts.DRIVER,
|
|
||||||
default='vitrage.datasources.static_physical.driver.'
|
|
||||||
'StaticPhysicalDriver',
|
|
||||||
help='Static physical driver class path',
|
|
||||||
required=True),
|
|
||||||
cfg.StrOpt(DSOpts.UPDATE_METHOD,
|
|
||||||
default=UpdateMethod.PULL,
|
|
||||||
help='None: updates only via Vitrage periodic snapshots.'
|
|
||||||
'Pull: updates every [changes_interval] seconds.'
|
|
||||||
'Push: updates by getting notifications from the'
|
|
||||||
' datasource itself.',
|
|
||||||
deprecated_for_removal=True,
|
|
||||||
deprecated_reason=_DEPRECATED_MSG,
|
|
||||||
deprecated_since=versionutils.deprecated.QUEENS,
|
|
||||||
required=True),
|
|
||||||
cfg.IntOpt(DSOpts.CHANGES_INTERVAL,
|
|
||||||
default=20,
|
|
||||||
min=5,
|
|
||||||
help='interval between checking changes in the configuration '
|
|
||||||
'files of the physical topology data sources',
|
|
||||||
deprecated_for_removal=True,
|
|
||||||
deprecated_reason=_DEPRECATED_MSG,
|
|
||||||
deprecated_since=versionutils.deprecated.QUEENS),
|
|
||||||
|
|
||||||
cfg.StrOpt('directory', default='/etc/vitrage/static_datasources',
|
|
||||||
help='Static physical data sources directory',
|
|
||||||
deprecated_for_removal=True,
|
|
||||||
deprecated_reason=_DEPRECATED_MSG,
|
|
||||||
deprecated_since=versionutils.deprecated.QUEENS),
|
|
||||||
cfg.ListOpt('entities',
|
|
||||||
default=[SWITCH],
|
|
||||||
help='Static physical entity types list',
|
|
||||||
deprecated_for_removal=True,
|
|
||||||
deprecated_reason=_DEPRECATED_MSG,
|
|
||||||
deprecated_since=versionutils.deprecated.QUEENS)
|
|
||||||
]
|
|
@ -1,167 +0,0 @@
|
|||||||
# 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 copy
|
|
||||||
|
|
||||||
from debtcollector import removals
|
|
||||||
from oslo_log import log
|
|
||||||
|
|
||||||
from vitrage.common.constants import DatasourceProperties as DSProps
|
|
||||||
from vitrage.common.constants import GraphAction
|
|
||||||
from vitrage.datasources.driver_base import DriverBase
|
|
||||||
from vitrage.datasources.static.driver import StaticDriver
|
|
||||||
from vitrage.datasources.static import StaticFields
|
|
||||||
from vitrage.datasources.static_physical import STATIC_PHYSICAL_DATASOURCE
|
|
||||||
from vitrage.utils import file as file_utils
|
|
||||||
|
|
||||||
LOG = log.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
class StaticPhysicalDriver(DriverBase):
|
|
||||||
@staticmethod
|
|
||||||
def get_event_types():
|
|
||||||
return []
|
|
||||||
|
|
||||||
def enrich_event(self, event, event_type):
|
|
||||||
pass
|
|
||||||
|
|
||||||
ENTITIES_SECTION = 'entities'
|
|
||||||
|
|
||||||
def __init__(self, conf):
|
|
||||||
removals.removed_module(__name__, "datasources.static")
|
|
||||||
super(StaticPhysicalDriver, self).__init__()
|
|
||||||
self.cfg = conf
|
|
||||||
self.cache = {}
|
|
||||||
|
|
||||||
def get_all(self, datasource_action):
|
|
||||||
return self.make_pickleable(self._get_all_entities(),
|
|
||||||
STATIC_PHYSICAL_DATASOURCE,
|
|
||||||
datasource_action)
|
|
||||||
|
|
||||||
def get_changes(self, datasource_action):
|
|
||||||
return self.make_pickleable(self._get_changes_entities(),
|
|
||||||
STATIC_PHYSICAL_DATASOURCE,
|
|
||||||
datasource_action)
|
|
||||||
|
|
||||||
def _get_all_entities(self):
|
|
||||||
static_entities = []
|
|
||||||
|
|
||||||
files = file_utils.list_files(
|
|
||||||
self.cfg.static_physical.directory, '.yaml')
|
|
||||||
|
|
||||||
for file_ in files:
|
|
||||||
full_path = self.cfg.static_physical.directory \
|
|
||||||
+ '/' + file_
|
|
||||||
static_entities += self._get_entities_from_file(file_,
|
|
||||||
full_path)
|
|
||||||
|
|
||||||
return static_entities
|
|
||||||
|
|
||||||
def _get_entities_from_file(self, file_, path):
|
|
||||||
static_entities = []
|
|
||||||
config = file_utils.load_yaml_file(path)
|
|
||||||
|
|
||||||
if StaticDriver._is_valid_config(config):
|
|
||||||
LOG.warning("Skipped config of new static datasource: {}"
|
|
||||||
.format(file_))
|
|
||||||
return []
|
|
||||||
|
|
||||||
for entity in config[self.ENTITIES_SECTION]:
|
|
||||||
static_entities.append(entity.copy())
|
|
||||||
|
|
||||||
self.cache[file_] = config
|
|
||||||
|
|
||||||
return static_entities
|
|
||||||
|
|
||||||
def _get_changes_entities(self):
|
|
||||||
|
|
||||||
entities_updates = []
|
|
||||||
files = file_utils.list_files(
|
|
||||||
self.cfg.static_physical.directory, '.yaml')
|
|
||||||
|
|
||||||
for file_ in files:
|
|
||||||
full_path = self.cfg.static_physical.directory +\
|
|
||||||
'/' + file_
|
|
||||||
config = file_utils.load_yaml_file(full_path)
|
|
||||||
|
|
||||||
if StaticDriver._is_valid_config(config):
|
|
||||||
LOG.warning("Skipped config of new static datasource: {}"
|
|
||||||
.format(file_))
|
|
||||||
return []
|
|
||||||
|
|
||||||
if config:
|
|
||||||
if file_ in self.cache:
|
|
||||||
if str(config) != str(self.cache[file_]):
|
|
||||||
# TODO(alexey_weyl): need also to remove deleted
|
|
||||||
# files from cache
|
|
||||||
old_config = copy.deepcopy(config)
|
|
||||||
|
|
||||||
self._update_on_existing_entities(
|
|
||||||
self.cache[file_][self.ENTITIES_SECTION],
|
|
||||||
config[self.ENTITIES_SECTION],
|
|
||||||
entities_updates)
|
|
||||||
|
|
||||||
self._update_on_new_entities(
|
|
||||||
config[self.ENTITIES_SECTION],
|
|
||||||
self.cache[file_][self.ENTITIES_SECTION],
|
|
||||||
entities_updates)
|
|
||||||
|
|
||||||
self.cache[file_] = old_config
|
|
||||||
else:
|
|
||||||
self.cache[file_] = config
|
|
||||||
entities_updates += \
|
|
||||||
self._get_entities_from_file(file_, full_path)
|
|
||||||
|
|
||||||
# iterate over deleted files
|
|
||||||
deleted_files = set(self.cache.keys()) - set(files)
|
|
||||||
for file_ in deleted_files:
|
|
||||||
self._update_on_existing_entities(
|
|
||||||
self.cache[file_][self.ENTITIES_SECTION],
|
|
||||||
{},
|
|
||||||
entities_updates)
|
|
||||||
del self.cache[file_]
|
|
||||||
|
|
||||||
return entities_updates
|
|
||||||
|
|
||||||
def _update_on_existing_entities(self,
|
|
||||||
old_entities,
|
|
||||||
new_entities,
|
|
||||||
updates):
|
|
||||||
for old_entity in old_entities:
|
|
||||||
if not new_entities or old_entity not in new_entities:
|
|
||||||
new_entity = self._find_entity(old_entity, new_entities)
|
|
||||||
if not new_entity:
|
|
||||||
self._set_event_type(old_entity, GraphAction.DELETE_ENTITY)
|
|
||||||
updates.append(old_entity.copy())
|
|
||||||
else:
|
|
||||||
self._set_event_type(new_entity, GraphAction.UPDATE_ENTITY)
|
|
||||||
updates.append(new_entity.copy())
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _find_entity(new_entity, entities):
|
|
||||||
for entity in entities:
|
|
||||||
if entity[StaticFields.TYPE] == new_entity[StaticFields.TYPE] \
|
|
||||||
and entity[StaticFields.ID] == new_entity[StaticFields.ID]:
|
|
||||||
return entity
|
|
||||||
return None
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _update_on_new_entities(new_entities, old_entities, updates):
|
|
||||||
for entity in new_entities:
|
|
||||||
if entity not in updates and entity not in old_entities:
|
|
||||||
updates.append(entity.copy())
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _set_event_type(entity, event_type):
|
|
||||||
entity[DSProps.EVENT_TYPE] = event_type
|
|
@ -1,128 +0,0 @@
|
|||||||
# 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.
|
|
||||||
|
|
||||||
from debtcollector import removals
|
|
||||||
from vitrage.common.constants import DatasourceProperties as DSProps
|
|
||||||
from vitrage.common.constants import EntityCategory
|
|
||||||
from vitrage.common.constants import GraphAction
|
|
||||||
from vitrage.common.constants import VertexProperties as VProps
|
|
||||||
from vitrage.datasources.nova.host import NOVA_HOST_DATASOURCE
|
|
||||||
from vitrage.datasources.resource_transformer_base import \
|
|
||||||
ResourceTransformerBase
|
|
||||||
from vitrage.datasources.static import StaticFields
|
|
||||||
from vitrage.datasources.static_physical import STATIC_PHYSICAL_DATASOURCE
|
|
||||||
from vitrage.datasources.static_physical import SWITCH
|
|
||||||
from vitrage.datasources import transformer_base
|
|
||||||
import vitrage.graph.utils as graph_utils
|
|
||||||
|
|
||||||
|
|
||||||
class StaticPhysicalTransformer(ResourceTransformerBase):
|
|
||||||
|
|
||||||
RELATION_TYPE = 'relation_type'
|
|
||||||
RELATIONSHIPS_SECTION = 'relationships'
|
|
||||||
|
|
||||||
# graph actions which need to refer them differently
|
|
||||||
GRAPH_ACTION_MAPPING = {
|
|
||||||
GraphAction.DELETE_ENTITY: GraphAction.DELETE_ENTITY
|
|
||||||
}
|
|
||||||
|
|
||||||
def __init__(self, transformers, conf):
|
|
||||||
removals.removed_module(__name__, "datasources.static")
|
|
||||||
super(StaticPhysicalTransformer, self).__init__(transformers, conf)
|
|
||||||
self._register_relations_direction()
|
|
||||||
|
|
||||||
def _create_snapshot_entity_vertex(self, entity_event):
|
|
||||||
return self._create_vertex(entity_event)
|
|
||||||
|
|
||||||
def _create_update_entity_vertex(self, entity_event):
|
|
||||||
return self._create_vertex(entity_event)
|
|
||||||
|
|
||||||
def _create_vertex(self, entity_event):
|
|
||||||
|
|
||||||
entity_type = entity_event[StaticFields.TYPE]
|
|
||||||
entity_id = entity_event[VProps.ID]
|
|
||||||
vitrage_sample_timestamp = entity_event[DSProps.SAMPLE_DATE]
|
|
||||||
update_timestamp = self._format_update_timestamp(
|
|
||||||
update_timestamp=None,
|
|
||||||
sample_timestamp=vitrage_sample_timestamp)
|
|
||||||
state = entity_event[VProps.STATE]
|
|
||||||
entity_key = self._create_entity_key(entity_event)
|
|
||||||
metadata = self._extract_metadata(entity_event)
|
|
||||||
|
|
||||||
return graph_utils.create_vertex(
|
|
||||||
entity_key,
|
|
||||||
vitrage_category=EntityCategory.RESOURCE,
|
|
||||||
vitrage_type=entity_type,
|
|
||||||
vitrage_sample_timestamp=vitrage_sample_timestamp,
|
|
||||||
entity_id=entity_id,
|
|
||||||
update_timestamp=update_timestamp,
|
|
||||||
entity_state=state,
|
|
||||||
metadata=metadata)
|
|
||||||
|
|
||||||
def _create_snapshot_neighbors(self, entity_event):
|
|
||||||
return self._create_static_physical_neighbors(entity_event)
|
|
||||||
|
|
||||||
def _create_update_neighbors(self, entity_event):
|
|
||||||
return self._create_static_physical_neighbors(entity_event)
|
|
||||||
|
|
||||||
def _create_static_physical_neighbors(self, entity_event):
|
|
||||||
neighbors = []
|
|
||||||
entity_type = entity_event[StaticFields.TYPE]
|
|
||||||
|
|
||||||
for neighbor_details in entity_event.get(
|
|
||||||
self.RELATIONSHIPS_SECTION, {}):
|
|
||||||
# TODO(alexey): need to decide what to do if one of the entities
|
|
||||||
# fails
|
|
||||||
neighbor_id = neighbor_details[VProps.ID]
|
|
||||||
neighbor_type = neighbor_details[StaticFields.TYPE]
|
|
||||||
relation_type = neighbor_details[self.RELATION_TYPE]
|
|
||||||
is_entity_source = not self._find_relation_direction_source(
|
|
||||||
entity_type, neighbor_type)
|
|
||||||
neighbor = self._create_neighbor(entity_event,
|
|
||||||
neighbor_id,
|
|
||||||
neighbor_type,
|
|
||||||
relation_type,
|
|
||||||
is_entity_source=is_entity_source)
|
|
||||||
if neighbor is not None:
|
|
||||||
neighbors.append(neighbor)
|
|
||||||
|
|
||||||
return neighbors
|
|
||||||
|
|
||||||
def _create_entity_key(self, entity_event):
|
|
||||||
entity_id = entity_event[VProps.ID]
|
|
||||||
entity_type = entity_event[StaticFields.TYPE]
|
|
||||||
key_fields = self._key_values(entity_type, entity_id)
|
|
||||||
return transformer_base.build_key(key_fields)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _extract_metadata(entity_event):
|
|
||||||
metadata = {VProps.NAME: entity_event[VProps.NAME]}
|
|
||||||
return metadata
|
|
||||||
|
|
||||||
def _find_relation_direction_source(self, entity_type, neighbor_type):
|
|
||||||
# TODO(alexey): maybe check if this type exists, because it throws
|
|
||||||
# exception if it doesn't
|
|
||||||
return self.relation_direction[(entity_type, neighbor_type)]
|
|
||||||
|
|
||||||
def _register_relations_direction(self):
|
|
||||||
self.relation_direction = {}
|
|
||||||
|
|
||||||
relationship = (SWITCH, NOVA_HOST_DATASOURCE)
|
|
||||||
self.relation_direction[relationship] = True
|
|
||||||
|
|
||||||
relationship = (SWITCH, SWITCH)
|
|
||||||
self.relation_direction[relationship] = True
|
|
||||||
|
|
||||||
def get_vitrage_type(self):
|
|
||||||
return STATIC_PHYSICAL_DATASOURCE
|
|
@ -1,99 +0,0 @@
|
|||||||
# 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.
|
|
||||||
|
|
||||||
from oslo_config import cfg
|
|
||||||
from testtools import matchers
|
|
||||||
|
|
||||||
from vitrage.common.constants import DatasourceProperties as DSProps
|
|
||||||
from vitrage.common.constants import EntityCategory
|
|
||||||
from vitrage.common.constants import VertexProperties as VProps
|
|
||||||
from vitrage.datasources.nagios import NAGIOS_DATASOURCE
|
|
||||||
from vitrage.datasources import NOVA_HOST_DATASOURCE
|
|
||||||
from vitrage.datasources import NOVA_INSTANCE_DATASOURCE
|
|
||||||
from vitrage.datasources import NOVA_ZONE_DATASOURCE
|
|
||||||
from vitrage.datasources.static_physical import STATIC_PHYSICAL_DATASOURCE
|
|
||||||
from vitrage.datasources.static_physical import SWITCH
|
|
||||||
from vitrage.tests.functional.datasources.base import \
|
|
||||||
TestDataSourcesBase
|
|
||||||
from vitrage.tests.mocks import mock_driver
|
|
||||||
|
|
||||||
|
|
||||||
class TestStaticPhysical(TestDataSourcesBase):
|
|
||||||
|
|
||||||
DATASOURCES_OPTS = [
|
|
||||||
cfg.ListOpt('types',
|
|
||||||
default=[NAGIOS_DATASOURCE,
|
|
||||||
NOVA_HOST_DATASOURCE,
|
|
||||||
NOVA_INSTANCE_DATASOURCE,
|
|
||||||
NOVA_ZONE_DATASOURCE,
|
|
||||||
STATIC_PHYSICAL_DATASOURCE],
|
|
||||||
help='Names of supported driver data sources'),
|
|
||||||
|
|
||||||
cfg.ListOpt('path',
|
|
||||||
default=['vitrage.datasources'],
|
|
||||||
help='base path for data sources')
|
|
||||||
]
|
|
||||||
|
|
||||||
# noinspection PyPep8Naming
|
|
||||||
@classmethod
|
|
||||||
def setUpClass(cls):
|
|
||||||
super(TestStaticPhysical, cls).setUpClass()
|
|
||||||
cls.conf = cfg.ConfigOpts()
|
|
||||||
cls.conf.register_opts(cls.PROCESSOR_OPTS, group='entity_graph')
|
|
||||||
cls.conf.register_opts(cls.DATASOURCES_OPTS, group='datasources')
|
|
||||||
cls.load_datasources(cls.conf)
|
|
||||||
|
|
||||||
def test_static_physical_validity(self):
|
|
||||||
# Setup
|
|
||||||
processor = self._create_processor_with_graph(self.conf)
|
|
||||||
transformers = processor.transformer_manager.transformers
|
|
||||||
transformers[SWITCH] = transformers[STATIC_PHYSICAL_DATASOURCE]
|
|
||||||
self.assertThat(processor.entity_graph,
|
|
||||||
matchers.HasLength(
|
|
||||||
self._num_total_expected_vertices())
|
|
||||||
)
|
|
||||||
|
|
||||||
spec_list = mock_driver.simple_switch_generators(
|
|
||||||
switch_num=1,
|
|
||||||
host_num=1,
|
|
||||||
snapshot_events=1)
|
|
||||||
static_events = mock_driver.generate_random_events_list(spec_list)
|
|
||||||
static_physical_event = static_events[0]
|
|
||||||
static_physical_event[DSProps.ENTITY_TYPE] = SWITCH
|
|
||||||
static_physical_event['relationships'][0]['name'] = \
|
|
||||||
self._find_entity_id_by_type(processor.entity_graph,
|
|
||||||
NOVA_HOST_DATASOURCE)
|
|
||||||
|
|
||||||
# Action
|
|
||||||
processor.process_event(static_physical_event)
|
|
||||||
|
|
||||||
# Test assertions
|
|
||||||
self.assertThat(processor.entity_graph,
|
|
||||||
matchers.HasLength(
|
|
||||||
self._num_total_expected_vertices() + 1)
|
|
||||||
)
|
|
||||||
|
|
||||||
static_physical_vertices = processor.entity_graph.get_vertices(
|
|
||||||
vertex_attr_filter={
|
|
||||||
VProps.VITRAGE_CATEGORY: EntityCategory.RESOURCE,
|
|
||||||
VProps.VITRAGE_TYPE: SWITCH
|
|
||||||
})
|
|
||||||
self.assertThat(static_physical_vertices, matchers.HasLength(1))
|
|
||||||
|
|
||||||
static_physical_neighbors = processor.entity_graph.neighbors(
|
|
||||||
static_physical_vertices[0].vertex_id)
|
|
||||||
self.assertThat(static_physical_neighbors, matchers.HasLength(1))
|
|
||||||
|
|
||||||
self.assertEqual(NOVA_HOST_DATASOURCE,
|
|
||||||
static_physical_neighbors[0][VProps.VITRAGE_TYPE])
|
|
@ -317,56 +317,6 @@ def simple_consistency_generators(consistency_num, update_events=0,
|
|||||||
return tg.get_trace_generators(test_entity_spec_list)
|
return tg.get_trace_generators(test_entity_spec_list)
|
||||||
|
|
||||||
|
|
||||||
def simple_switch_generators(switch_num, host_num,
|
|
||||||
snapshot_events=0, snap_vals=None,
|
|
||||||
update_events=0, update_vals=None):
|
|
||||||
"""A function for returning switch events generators.
|
|
||||||
|
|
||||||
Returns generators for a given number of switches and hosts.
|
|
||||||
Hosts will be distributed across switches in round-robin style.
|
|
||||||
Switches are interconnected in a line.
|
|
||||||
|
|
||||||
:param update_vals: number of events from update event
|
|
||||||
:param update_events: number of values from update event
|
|
||||||
:param switch_num: number of zones
|
|
||||||
:param host_num: number of hosts
|
|
||||||
:param snapshot_events: number of snapshot events per zone
|
|
||||||
:param snap_vals: preset values for ALL snapshot events
|
|
||||||
:return: generators for switch events as specified
|
|
||||||
"""
|
|
||||||
|
|
||||||
mapping = [('host-{0}'.format(index), 'switch-{0}'.format(index %
|
|
||||||
switch_num))
|
|
||||||
for index in range(host_num)
|
|
||||||
]
|
|
||||||
|
|
||||||
test_entity_spec_list = []
|
|
||||||
if snapshot_events:
|
|
||||||
test_entity_spec_list.append(
|
|
||||||
{tg.DYNAMIC_INFO_FKEY: tg.DRIVER_SWITCH_SNAPSHOT_D,
|
|
||||||
tg.STATIC_INFO_FKEY: None,
|
|
||||||
tg.EXTERNAL_INFO_KEY: snap_vals,
|
|
||||||
tg.MAPPING_KEY: mapping,
|
|
||||||
tg.NAME_KEY: 'Switch snapshot generator',
|
|
||||||
tg.NUM_EVENTS: snapshot_events
|
|
||||||
}
|
|
||||||
)
|
|
||||||
if update_events:
|
|
||||||
update_vals = {} if not update_vals else update_vals
|
|
||||||
update_vals[DSProps.DATASOURCE_ACTION] = \
|
|
||||||
DatasourceAction.UPDATE
|
|
||||||
test_entity_spec_list.append(
|
|
||||||
{tg.DYNAMIC_INFO_FKEY: tg.DRIVER_SWITCH_SNAPSHOT_D,
|
|
||||||
tg.STATIC_INFO_FKEY: None,
|
|
||||||
tg.EXTERNAL_INFO_KEY: update_vals,
|
|
||||||
tg.MAPPING_KEY: mapping,
|
|
||||||
tg.NAME_KEY: 'Switch update generator',
|
|
||||||
tg.NUM_EVENTS: update_events
|
|
||||||
}
|
|
||||||
)
|
|
||||||
return tg.get_trace_generators(test_entity_spec_list)
|
|
||||||
|
|
||||||
|
|
||||||
def simple_static_generators(switch_num=2, host_num=10,
|
def simple_static_generators(switch_num=2, host_num=10,
|
||||||
snapshot_events=0, snap_vals=None,
|
snapshot_events=0, snap_vals=None,
|
||||||
update_events=0, update_vals=None):
|
update_events=0, update_vals=None):
|
||||||
|
@ -58,7 +58,6 @@ DRIVER_NAGIOS_SNAPSHOT_D = 'driver_nagios_snapshot_dynamic.json'
|
|||||||
DRIVER_NAGIOS_SNAPSHOT_S = 'driver_nagios_snapshot_static.json'
|
DRIVER_NAGIOS_SNAPSHOT_S = 'driver_nagios_snapshot_static.json'
|
||||||
DRIVER_PROMETHEUS_UPDATE_D = 'driver_prometheus_update_dynamic.json'
|
DRIVER_PROMETHEUS_UPDATE_D = 'driver_prometheus_update_dynamic.json'
|
||||||
DRIVER_ZABBIX_SNAPSHOT_D = 'driver_zabbix_snapshot_dynamic.json'
|
DRIVER_ZABBIX_SNAPSHOT_D = 'driver_zabbix_snapshot_dynamic.json'
|
||||||
DRIVER_SWITCH_SNAPSHOT_D = 'driver_switch_snapshot_dynamic.json'
|
|
||||||
DRIVER_STATIC_SNAPSHOT_D = 'driver_static_snapshot_dynamic.json'
|
DRIVER_STATIC_SNAPSHOT_D = 'driver_static_snapshot_dynamic.json'
|
||||||
DRIVER_STATIC_SNAPSHOT_S = 'driver_static_snapshot_static.json'
|
DRIVER_STATIC_SNAPSHOT_S = 'driver_static_snapshot_static.json'
|
||||||
DRIVER_VOLUME_UPDATE_D = 'driver_volume_update_dynamic.json'
|
DRIVER_VOLUME_UPDATE_D = 'driver_volume_update_dynamic.json'
|
||||||
@ -131,7 +130,6 @@ class EventTraceGenerator(object):
|
|||||||
DRIVER_VOLUME_UPDATE_D: _get_volume_update_driver_values,
|
DRIVER_VOLUME_UPDATE_D: _get_volume_update_driver_values,
|
||||||
DRIVER_STACK_SNAPSHOT_D: _get_stack_snapshot_driver_values,
|
DRIVER_STACK_SNAPSHOT_D: _get_stack_snapshot_driver_values,
|
||||||
DRIVER_STACK_UPDATE_D: _get_stack_update_driver_values,
|
DRIVER_STACK_UPDATE_D: _get_stack_update_driver_values,
|
||||||
DRIVER_SWITCH_SNAPSHOT_D: _get_switch_snapshot_driver_values,
|
|
||||||
DRIVER_STATIC_SNAPSHOT_D: _get_static_snapshot_driver_values,
|
DRIVER_STATIC_SNAPSHOT_D: _get_static_snapshot_driver_values,
|
||||||
DRIVER_NAGIOS_SNAPSHOT_D: _get_nagios_alarm_driver_values,
|
DRIVER_NAGIOS_SNAPSHOT_D: _get_nagios_alarm_driver_values,
|
||||||
DRIVER_ZABBIX_SNAPSHOT_D: _get_zabbix_alarm_driver_values,
|
DRIVER_ZABBIX_SNAPSHOT_D: _get_zabbix_alarm_driver_values,
|
||||||
@ -513,46 +511,6 @@ def _get_vm_update_driver_values(spec):
|
|||||||
return static_values
|
return static_values
|
||||||
|
|
||||||
|
|
||||||
def _get_switch_snapshot_driver_values(spec):
|
|
||||||
"""Generates the static driver values for each zone.
|
|
||||||
|
|
||||||
:param spec: specification of event generation.
|
|
||||||
:type spec: dict
|
|
||||||
:return: list of static driver values for each zone.
|
|
||||||
:rtype: list
|
|
||||||
"""
|
|
||||||
|
|
||||||
host_switch_mapping = spec[MAPPING_KEY]
|
|
||||||
static_info = None
|
|
||||||
if spec[STATIC_INFO_FKEY] is not None:
|
|
||||||
static_info = utils.load_specs(spec[STATIC_INFO_FKEY])
|
|
||||||
|
|
||||||
static_values = []
|
|
||||||
|
|
||||||
switches_info = {}
|
|
||||||
for host_name, switch_name in host_switch_mapping:
|
|
||||||
switch_info = switches_info.get(switch_name, [])
|
|
||||||
|
|
||||||
relationship_info = {"type": NOVA_HOST_DATASOURCE,
|
|
||||||
"name": host_name,
|
|
||||||
"id": host_name,
|
|
||||||
"relation_type": "contains"
|
|
||||||
}
|
|
||||||
|
|
||||||
switch_info.append(relationship_info)
|
|
||||||
switches_info[switch_name] = switch_info
|
|
||||||
|
|
||||||
for host_name, switch_name in host_switch_mapping:
|
|
||||||
mapping = {'name': switch_name,
|
|
||||||
'id': switch_name,
|
|
||||||
'relationships': switches_info[switch_name]
|
|
||||||
}
|
|
||||||
static_values.append(combine_data(static_info,
|
|
||||||
mapping,
|
|
||||||
spec.get(EXTERNAL_INFO_KEY, None)))
|
|
||||||
return static_values
|
|
||||||
|
|
||||||
|
|
||||||
def _get_static_snapshot_driver_values(spec):
|
def _get_static_snapshot_driver_values(spec):
|
||||||
"""Generates the static driver values for static datasource.
|
"""Generates the static driver values for static datasource.
|
||||||
|
|
||||||
|
@ -1,16 +0,0 @@
|
|||||||
{
|
|
||||||
"relationships": [
|
|
||||||
{"type": "nova.host",
|
|
||||||
"name": "host-[1-9]",
|
|
||||||
"id": "[1-9]{5}",
|
|
||||||
"relation_type": "contains"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "switch-[0-9]",
|
|
||||||
"id": "[1-9]{5}",
|
|
||||||
"vitrage_sample_date": "2015-12-01T12:46:41Z",
|
|
||||||
"type": "switch",
|
|
||||||
"vitrage_datasource_action": "snapshot",
|
|
||||||
"state": "available",
|
|
||||||
"vitrage_event_type": "entity_update"
|
|
||||||
}
|
|
@ -1,145 +0,0 @@
|
|||||||
# 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 os
|
|
||||||
|
|
||||||
from oslo_config import cfg
|
|
||||||
from testtools import matchers
|
|
||||||
|
|
||||||
from vitrage.common.constants import DatasourceAction
|
|
||||||
from vitrage.common.constants import DatasourceOpts as DSOpts
|
|
||||||
from vitrage.common.constants import DatasourceProperties as DSProps
|
|
||||||
from vitrage.common.constants import GraphAction
|
|
||||||
from vitrage.datasources.static import StaticFields
|
|
||||||
from vitrage.datasources.static_physical import driver
|
|
||||||
from vitrage.datasources.static_physical import STATIC_PHYSICAL_DATASOURCE
|
|
||||||
from vitrage.datasources.static_physical import SWITCH
|
|
||||||
from vitrage.tests import base
|
|
||||||
from vitrage.tests.base import IsEmpty
|
|
||||||
from vitrage.tests.mocks import utils
|
|
||||||
from vitrage.utils import file as file_utils
|
|
||||||
|
|
||||||
|
|
||||||
class TestStaticPhysicalDriver(base.BaseTest):
|
|
||||||
|
|
||||||
OPTS = [
|
|
||||||
cfg.StrOpt(DSOpts.TRANSFORMER,
|
|
||||||
default='vitrage.datasources.static_physical.transformer.'
|
|
||||||
'StaticPhysicalTransformer'),
|
|
||||||
cfg.StrOpt(DSOpts.DRIVER,
|
|
||||||
default='vitrage.datasources.static_physical.driver.'
|
|
||||||
'StaticPhysicalDriver'),
|
|
||||||
cfg.IntOpt(DSOpts.CHANGES_INTERVAL,
|
|
||||||
default=30,
|
|
||||||
min=30,
|
|
||||||
help='interval between checking changes in the '
|
|
||||||
'configuration files of the physical topology plugin'),
|
|
||||||
cfg.StrOpt('directory',
|
|
||||||
default=utils.get_resources_dir() + '/static_datasources'),
|
|
||||||
cfg.ListOpt('entities',
|
|
||||||
default=[SWITCH])
|
|
||||||
]
|
|
||||||
|
|
||||||
CHANGES_OPTS = [
|
|
||||||
cfg.StrOpt(DSOpts.TRANSFORMER,
|
|
||||||
default='vitrage.datasources.static_physical.transformer.'
|
|
||||||
'StaticPhysicalTransformer'),
|
|
||||||
cfg.StrOpt(DSOpts.DRIVER,
|
|
||||||
default='vitrage.datasources.static_physical.driver.'
|
|
||||||
'StaticPhysicalDriver'),
|
|
||||||
cfg.IntOpt(DSOpts.CHANGES_INTERVAL,
|
|
||||||
default=30,
|
|
||||||
min=30,
|
|
||||||
help='interval between checking changes in the '
|
|
||||||
'configuration files of the physical topology plugin'),
|
|
||||||
cfg.StrOpt('directory',
|
|
||||||
default=utils.get_resources_dir() +
|
|
||||||
'/static_datasources/changes_datasources'),
|
|
||||||
]
|
|
||||||
|
|
||||||
# noinspection PyAttributeOutsideInit,PyPep8Naming
|
|
||||||
@classmethod
|
|
||||||
def setUpClass(cls):
|
|
||||||
super(TestStaticPhysicalDriver, cls).setUpClass()
|
|
||||||
cls.conf = cfg.ConfigOpts()
|
|
||||||
cls.conf.register_opts(cls.OPTS, group=STATIC_PHYSICAL_DATASOURCE)
|
|
||||||
cls.static_physical_driver = driver.StaticPhysicalDriver(cls.conf)
|
|
||||||
|
|
||||||
def test_static_datasources_loader(self):
|
|
||||||
# Setup
|
|
||||||
total_static_datasources = \
|
|
||||||
os.listdir(self.conf.static_physical.directory)
|
|
||||||
|
|
||||||
# Action
|
|
||||||
static_configs = file_utils.load_yaml_files(
|
|
||||||
self.conf.static_physical.directory)
|
|
||||||
|
|
||||||
# Test assertions
|
|
||||||
# -1 is because there are 2 files and a folder in static_datasource_dir
|
|
||||||
self.assertEqual(len(total_static_datasources) - 1,
|
|
||||||
len(static_configs))
|
|
||||||
|
|
||||||
def test_get_all(self):
|
|
||||||
# Action
|
|
||||||
static_entities = \
|
|
||||||
self.static_physical_driver.get_all(DatasourceAction.UPDATE)
|
|
||||||
|
|
||||||
# Test assertions
|
|
||||||
self.assertThat(static_entities, matchers.HasLength(5))
|
|
||||||
|
|
||||||
# noinspection PyAttributeOutsideInit
|
|
||||||
def test_get_changes(self):
|
|
||||||
# Setup
|
|
||||||
entities = self.static_physical_driver.get_all(DatasourceAction.UPDATE)
|
|
||||||
self.assertThat(entities, matchers.HasLength(5))
|
|
||||||
|
|
||||||
self.conf = cfg.ConfigOpts()
|
|
||||||
self.conf.register_opts(self.CHANGES_OPTS,
|
|
||||||
group=STATIC_PHYSICAL_DATASOURCE)
|
|
||||||
self.static_physical_driver.cfg = self.conf
|
|
||||||
|
|
||||||
# Action
|
|
||||||
changes = self.static_physical_driver.get_changes(
|
|
||||||
GraphAction.UPDATE_ENTITY)
|
|
||||||
|
|
||||||
# Test Assertions
|
|
||||||
status = any(change[StaticFields.TYPE] == SWITCH and
|
|
||||||
change[StaticFields.ID] == '12345' for change in changes)
|
|
||||||
self.assertFalse(status)
|
|
||||||
|
|
||||||
status = any(change[StaticFields.TYPE] == SWITCH and
|
|
||||||
change[StaticFields.ID] == '23456' and
|
|
||||||
change[DSProps.EVENT_TYPE] == GraphAction.DELETE_ENTITY
|
|
||||||
for change in changes)
|
|
||||||
self.assertTrue(status)
|
|
||||||
|
|
||||||
status = any(change[StaticFields.TYPE] == SWITCH and
|
|
||||||
change[StaticFields.ID] == '34567' for change in changes)
|
|
||||||
self.assertTrue(status)
|
|
||||||
|
|
||||||
status = any(change[StaticFields.TYPE] == SWITCH and
|
|
||||||
change[StaticFields.ID] == '45678' for change in changes)
|
|
||||||
self.assertTrue(status)
|
|
||||||
status = any(change[StaticFields.TYPE] == SWITCH and
|
|
||||||
change[StaticFields.ID] == '56789' for change in changes)
|
|
||||||
self.assertTrue(status)
|
|
||||||
|
|
||||||
self.assertThat(changes, matchers.HasLength(4))
|
|
||||||
|
|
||||||
# Action
|
|
||||||
changes = self.static_physical_driver.get_changes(
|
|
||||||
GraphAction.UPDATE_ENTITY)
|
|
||||||
|
|
||||||
# Test Assertions
|
|
||||||
self.assertThat(changes, IsEmpty())
|
|
@ -1,195 +0,0 @@
|
|||||||
# 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 datetime
|
|
||||||
|
|
||||||
from oslo_config import cfg
|
|
||||||
from oslo_log import log as logging
|
|
||||||
|
|
||||||
from vitrage.common.constants import DatasourceOpts as DSOpts
|
|
||||||
from vitrage.common.constants import DatasourceProperties as DSProps
|
|
||||||
from vitrage.common.constants import EdgeLabel
|
|
||||||
from vitrage.common.constants import EntityCategory
|
|
||||||
from vitrage.common.constants import UpdateMethod
|
|
||||||
from vitrage.common.constants import VertexProperties as VProps
|
|
||||||
from vitrage.datasources.nova.host import NOVA_HOST_DATASOURCE
|
|
||||||
from vitrage.datasources.nova.host.transformer import HostTransformer
|
|
||||||
from vitrage.datasources.static import StaticFields
|
|
||||||
from vitrage.datasources.static_physical import STATIC_PHYSICAL_DATASOURCE
|
|
||||||
from vitrage.datasources.static_physical.transformer \
|
|
||||||
import StaticPhysicalTransformer
|
|
||||||
from vitrage.datasources import transformer_base as tbase
|
|
||||||
from vitrage.datasources.transformer_base import TransformerBase
|
|
||||||
from vitrage.tests import base
|
|
||||||
from vitrage.tests.mocks import mock_driver as mock_sync
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
class TestStaticPhysicalTransformer(base.BaseTest):
|
|
||||||
|
|
||||||
OPTS = [
|
|
||||||
cfg.StrOpt(DSOpts.UPDATE_METHOD,
|
|
||||||
default=UpdateMethod.PULL),
|
|
||||||
]
|
|
||||||
|
|
||||||
# noinspection PyAttributeOutsideInit,PyPep8Naming
|
|
||||||
@classmethod
|
|
||||||
def setUpClass(cls):
|
|
||||||
super(TestStaticPhysicalTransformer, cls).setUpClass()
|
|
||||||
cls.transformers = {}
|
|
||||||
cls.conf = cfg.ConfigOpts()
|
|
||||||
cls.conf.register_opts(cls.OPTS, group=STATIC_PHYSICAL_DATASOURCE)
|
|
||||||
cls.transformers[NOVA_HOST_DATASOURCE] = HostTransformer(
|
|
||||||
cls.transformers, cls.conf)
|
|
||||||
cls.transformers[STATIC_PHYSICAL_DATASOURCE] = \
|
|
||||||
StaticPhysicalTransformer(cls.transformers, cls.conf)
|
|
||||||
|
|
||||||
def test_create_placeholder_vertex(self):
|
|
||||||
|
|
||||||
LOG.debug('Static Physical transformer test: Create placeholder '
|
|
||||||
'vertex')
|
|
||||||
|
|
||||||
# Test setup
|
|
||||||
switch_type = STATIC_PHYSICAL_DATASOURCE
|
|
||||||
switch_name = 'switch-1'
|
|
||||||
timestamp = datetime.datetime.utcnow()
|
|
||||||
static_transformer = self.transformers[STATIC_PHYSICAL_DATASOURCE]
|
|
||||||
|
|
||||||
# Test action
|
|
||||||
properties = {
|
|
||||||
VProps.VITRAGE_TYPE: switch_type,
|
|
||||||
VProps.ID: switch_name,
|
|
||||||
VProps.VITRAGE_CATEGORY: EntityCategory.RESOURCE,
|
|
||||||
VProps.VITRAGE_SAMPLE_TIMESTAMP: timestamp
|
|
||||||
}
|
|
||||||
placeholder = \
|
|
||||||
static_transformer.create_neighbor_placeholder_vertex(**properties)
|
|
||||||
|
|
||||||
# Test assertions
|
|
||||||
observed_uuid = placeholder.vertex_id
|
|
||||||
expected_key = tbase.build_key(static_transformer._key_values(
|
|
||||||
switch_type, switch_name))
|
|
||||||
expected_uuid = \
|
|
||||||
TransformerBase.uuid_from_deprecated_vitrage_id(expected_key)
|
|
||||||
self.assertEqual(expected_uuid, observed_uuid)
|
|
||||||
|
|
||||||
observed_time = placeholder.get(VProps.VITRAGE_SAMPLE_TIMESTAMP)
|
|
||||||
self.assertEqual(timestamp, observed_time)
|
|
||||||
|
|
||||||
observed_subtype = placeholder.get(VProps.VITRAGE_TYPE)
|
|
||||||
self.assertEqual(switch_type, observed_subtype)
|
|
||||||
|
|
||||||
observed_entity_id = placeholder.get(VProps.ID)
|
|
||||||
self.assertEqual(switch_name, observed_entity_id)
|
|
||||||
|
|
||||||
observed_vitrage_category = placeholder.get(VProps.VITRAGE_CATEGORY)
|
|
||||||
self.assertEqual(EntityCategory.RESOURCE, observed_vitrage_category)
|
|
||||||
|
|
||||||
vitrage_is_placeholder = placeholder.get(VProps.VITRAGE_IS_PLACEHOLDER)
|
|
||||||
self.assertTrue(vitrage_is_placeholder)
|
|
||||||
|
|
||||||
def test_key_values(self):
|
|
||||||
LOG.debug('Static Physical transformer test: get key values')
|
|
||||||
|
|
||||||
# Test setup
|
|
||||||
switch_type = STATIC_PHYSICAL_DATASOURCE
|
|
||||||
switch_name = 'switch-1'
|
|
||||||
static_transformer = self.transformers[STATIC_PHYSICAL_DATASOURCE]
|
|
||||||
|
|
||||||
# Test action
|
|
||||||
observed_key_fields = static_transformer._key_values(switch_type,
|
|
||||||
switch_name)
|
|
||||||
|
|
||||||
# Test assertions
|
|
||||||
self.assertEqual(EntityCategory.RESOURCE, observed_key_fields[0])
|
|
||||||
self.assertEqual(STATIC_PHYSICAL_DATASOURCE, observed_key_fields[1])
|
|
||||||
self.assertEqual(switch_name, observed_key_fields[2])
|
|
||||||
|
|
||||||
def test_snapshot_transform(self):
|
|
||||||
LOG.debug('Test transform entity snapshot/snapshot_init event')
|
|
||||||
|
|
||||||
# Test setup
|
|
||||||
spec_list = mock_sync.simple_switch_generators(2, 10, 10)
|
|
||||||
static_events = mock_sync.generate_random_events_list(spec_list)
|
|
||||||
self._events_transform_test(static_events)
|
|
||||||
|
|
||||||
def test_update_transform(self):
|
|
||||||
LOG.debug('Test transform entity update event')
|
|
||||||
|
|
||||||
# Test setup
|
|
||||||
spec_list = mock_sync.simple_switch_generators(2, 10, 0, None, 10)
|
|
||||||
static_events = mock_sync.generate_random_events_list(spec_list)
|
|
||||||
self._events_transform_test(static_events)
|
|
||||||
|
|
||||||
def _events_transform_test(self, events):
|
|
||||||
|
|
||||||
for event in events:
|
|
||||||
# Test action
|
|
||||||
wrapper = self.transformers[STATIC_PHYSICAL_DATASOURCE].\
|
|
||||||
transform(event)
|
|
||||||
|
|
||||||
# Test assertions
|
|
||||||
vertex = wrapper.vertex
|
|
||||||
self._validate_switch_vertex_props(vertex, event)
|
|
||||||
|
|
||||||
neighbors = wrapper.neighbors
|
|
||||||
self._validate_neighbors(neighbors, vertex.vertex_id, event)
|
|
||||||
|
|
||||||
def _validate_neighbors(self, neighbors, switch_vertex_id, event):
|
|
||||||
host_counter = 0
|
|
||||||
|
|
||||||
for neighbor in neighbors:
|
|
||||||
self._validate_host_neighbor(neighbor,
|
|
||||||
event['relationships'][host_counter],
|
|
||||||
switch_vertex_id)
|
|
||||||
host_counter += 1
|
|
||||||
|
|
||||||
self.assertEqual(5,
|
|
||||||
host_counter,
|
|
||||||
'Zone can belongs to only one Cluster')
|
|
||||||
|
|
||||||
def _validate_host_neighbor(self,
|
|
||||||
host_neighbor,
|
|
||||||
host_event,
|
|
||||||
switch_vertex_id):
|
|
||||||
# validate neighbor vertex
|
|
||||||
self._validate_host_vertex_props(host_neighbor.vertex, host_event)
|
|
||||||
|
|
||||||
# Validate neighbor edge
|
|
||||||
edge = host_neighbor.edge
|
|
||||||
self.assertEqual(edge.target_id, switch_vertex_id)
|
|
||||||
self.assertEqual(edge.source_id, host_neighbor.vertex.vertex_id)
|
|
||||||
self.assertEqual(edge.label, EdgeLabel.CONTAINS)
|
|
||||||
|
|
||||||
def _validate_common_vertex_props(self, vertex, event):
|
|
||||||
self.assertEqual(EntityCategory.RESOURCE,
|
|
||||||
vertex[VProps.VITRAGE_CATEGORY])
|
|
||||||
self.assertEqual(event[StaticFields.TYPE],
|
|
||||||
vertex[VProps.VITRAGE_TYPE])
|
|
||||||
self.assertEqual(event[StaticFields.ID], vertex[VProps.ID])
|
|
||||||
|
|
||||||
def _validate_switch_vertex_props(self, vertex, event):
|
|
||||||
self._validate_common_vertex_props(vertex, event)
|
|
||||||
self.assertEqual(event[DSProps.SAMPLE_DATE],
|
|
||||||
vertex[VProps.VITRAGE_SAMPLE_TIMESTAMP])
|
|
||||||
self.assertEqual(event[VProps.NAME], vertex[VProps.NAME])
|
|
||||||
self.assertEqual(event[VProps.STATE], vertex[VProps.STATE])
|
|
||||||
self.assertFalse(vertex[VProps.VITRAGE_IS_PLACEHOLDER])
|
|
||||||
self.assertFalse(vertex[VProps.VITRAGE_IS_DELETED])
|
|
||||||
|
|
||||||
def _validate_host_vertex_props(self, vertex, event):
|
|
||||||
self._validate_common_vertex_props(vertex, event)
|
|
||||||
self.assertTrue(vertex[VProps.VITRAGE_IS_PLACEHOLDER])
|
|
||||||
self.assertFalse(vertex[VProps.VITRAGE_IS_DELETED])
|
|
@ -31,7 +31,6 @@ from vitrage.common.exception import VitrageError
|
|||||||
from vitrage.datasources.nova.host import NOVA_HOST_DATASOURCE
|
from vitrage.datasources.nova.host import NOVA_HOST_DATASOURCE
|
||||||
from vitrage.datasources.nova.instance import NOVA_INSTANCE_DATASOURCE
|
from vitrage.datasources.nova.instance import NOVA_INSTANCE_DATASOURCE
|
||||||
from vitrage.datasources import OPENSTACK_CLUSTER
|
from vitrage.datasources import OPENSTACK_CLUSTER
|
||||||
from vitrage.datasources.static_physical import SWITCH
|
|
||||||
from vitrage.datasources.transformer_base import CLUSTER_ID
|
from vitrage.datasources.transformer_base import CLUSTER_ID
|
||||||
from vitrage.graph.driver.networkx_graph import NXGraph
|
from vitrage.graph.driver.networkx_graph import NXGraph
|
||||||
from vitrage.graph import utils as graph_utils
|
from vitrage.graph import utils as graph_utils
|
||||||
@ -80,9 +79,9 @@ v_alarm = graph_utils.create_vertex(
|
|||||||
metadata={VProps.RESOURCE_ID: '333333333333',
|
metadata={VProps.RESOURCE_ID: '333333333333',
|
||||||
VProps.NAME: 'anotheralarm'})
|
VProps.NAME: 'anotheralarm'})
|
||||||
v_switch = graph_utils.create_vertex(
|
v_switch = graph_utils.create_vertex(
|
||||||
vitrage_id=SWITCH + '1212121212',
|
vitrage_id='switch1212121212',
|
||||||
vitrage_category=RESOURCE,
|
vitrage_category=RESOURCE,
|
||||||
vitrage_type=SWITCH,
|
vitrage_type='switch',
|
||||||
entity_id='1212121212')
|
entity_id='1212121212')
|
||||||
|
|
||||||
e_node_to_host = graph_utils.create_edge(
|
e_node_to_host = graph_utils.create_edge(
|
||||||
|
@ -111,14 +111,14 @@ class GraphAlgorithmTest(GraphTestBase):
|
|||||||
|
|
||||||
query = {
|
query = {
|
||||||
'or': [
|
'or': [
|
||||||
{'==': {VProps.VITRAGE_TYPE: SWITCH}},
|
{'==': {VProps.VITRAGE_TYPE: 'switch'}},
|
||||||
{'==': {VProps.VITRAGE_TYPE: NOVA_HOST_DATASOURCE}},
|
{'==': {VProps.VITRAGE_TYPE: NOVA_HOST_DATASOURCE}},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
subgraph = ga.graph_query_vertices(
|
subgraph = ga.graph_query_vertices(
|
||||||
root_id=first_host_id, query_dict=query, depth=1)
|
root_id=first_host_id, query_dict=query, depth=1)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
1, # For SWITCH
|
1, # For 'switch'
|
||||||
subgraph.num_edges(), 'num of BOTH edges Host (depth 1)')
|
subgraph.num_edges(), 'num of BOTH edges Host (depth 1)')
|
||||||
|
|
||||||
subgraph = ga.graph_query_vertices(root_id=first_host_id, depth=2)
|
subgraph = ga.graph_query_vertices(root_id=first_host_id, depth=2)
|
||||||
@ -266,7 +266,7 @@ class GraphAlgorithmTest(GraphTestBase):
|
|||||||
t_v_vm_alarm = graph_utils.create_vertex(
|
t_v_vm_alarm = graph_utils.create_vertex(
|
||||||
vitrage_id='4', vitrage_category=ALARM, vitrage_type=ALARM_ON_VM)
|
vitrage_id='4', vitrage_category=ALARM, vitrage_type=ALARM_ON_VM)
|
||||||
t_v_switch = graph_utils.create_vertex(
|
t_v_switch = graph_utils.create_vertex(
|
||||||
vitrage_id='5', vitrage_category=RESOURCE, vitrage_type=SWITCH)
|
vitrage_id='5', vitrage_category=RESOURCE, vitrage_type='switch')
|
||||||
t_v_node = graph_utils.create_vertex(
|
t_v_node = graph_utils.create_vertex(
|
||||||
vitrage_id='6',
|
vitrage_id='6',
|
||||||
vitrage_category=RESOURCE,
|
vitrage_category=RESOURCE,
|
||||||
|
Loading…
Reference in New Issue
Block a user