Skip to content
Snippets Groups Projects
Commit 54c033b7 authored by aguilard's avatar aguilard
Browse files

Add VIO support in DAGs


Change-Id: I055587d4df315be45371cc84043cdc1f2e1b7888
Signed-off-by: default avataraguilard <e.dah.tid@telefonica.com>
parent 6fa799be
No related branches found
No related tags found
No related merge requests found
......@@ -85,7 +85,7 @@ def create_dag(dag_id, dag_number, dag_description, vim_id):
vim_type = vim_account["config"]["vim_type"].lower()
if vim_type == "vio" and "vrops_site" not in vim_account["config"]:
vim_type = "openstack"
if vim_type == "openstack":
if vim_type == "openstack" or vim_type == "vio":
return OpenStackCollector(vim_account)
if vim_type == "gcp":
return GcpCollector(vim_account)
......
......@@ -226,7 +226,7 @@ def create_dag(dag_id, dag_number, dag_description, vim_id):
vim_type = vim_account["config"]["vim_type"].lower()
if vim_type == "vio" and "vrops_site" not in vim_account["config"]:
vim_type = "openstack"
if vim_type == "openstack":
if vim_type == "openstack" or vim_type == "vio":
collector = OpenStackCollector(vim_account)
elif vim_type == "azure":
collector = AzureCollector(vim_account)
......
......@@ -86,7 +86,7 @@ def create_dag(dag_id, dag_number, dag_description, vim_id):
vim_type = vim_account["config"]["vim_type"].lower()
if vim_type == "vio" and "vrops_site" not in vim_account["config"]:
vim_type = "openstack"
if vim_type == "openstack":
if vim_type == "openstack" or vim_type == "vio":
return OpenStackCollector(vim_account)
if vim_type == "gcp":
return GcpCollector(vim_account)
......
......@@ -28,6 +28,7 @@ from keystoneauth1.exceptions.catalog import EndpointNotFound
from keystoneauth1.identity import v3
from novaclient import client as nova_client
from osm_mon.vim_connectors.base_vim import VIMConnector
from osm_mon.vim_connectors.vrops_helper import vROPS_Helper
from prometheus_api_client import PrometheusConnect as prometheus_client
log = logging.getLogger(__name__)
......@@ -95,7 +96,6 @@ class OpenStackCollector(VIMConnector):
self.vim_session = None
self.vim_session = self._get_session(vim_account)
self.nova = self._build_nova_client()
# self.gnocchi = self._build_gnocchi_client()
self.backend = self._get_backend(vim_account, self.vim_session)
def _get_session(self, creds: Dict):
......@@ -139,6 +139,20 @@ class OpenStackCollector(VIMConnector):
# log.error(f"Can't create prometheus client, {e}")
# return None
return None
if "config" in vim_account and "vim_type" in vim_account["config"]:
vim_type = vim_account["config"]["vim_type"].lower()
log.debug(f"vim_type: {vim_type}")
log.debug(f"vim_account[config]: {vim_account['config']}")
if vim_type == "vio" and "vrops_site" in vim_account["config"]:
try:
log.debug("Using vROPS backend to collect metric")
vrops = VropsBackend(vim_account)
return vrops
except Exception as e:
log.error(f"Can't create vROPS client, {e}")
return None
try:
gnocchi = GnocchiBackend(vim_account, vim_session)
gnocchi.client.metric.list(limit=1)
......@@ -196,6 +210,10 @@ class OpenStackCollector(VIMConnector):
log.info("Using Prometheus as backend (NOT SUPPORTED)")
return []
if type(self.backend) is VropsBackend:
log.info("Using vROPS as backend")
return self.backend.collect_metrics(metric_list)
metric_results = []
for metric in metric_list:
server = metric["vm_id"]
......@@ -224,6 +242,9 @@ class OpenstackBackend:
):
pass
def collect_metrics(self, metrics_list: List[Dict]):
pass
class PrometheusTSBDBackend(OpenstackBackend):
def __init__(self, vim_account: dict):
......@@ -418,3 +439,41 @@ class CeilometerBackend(OpenstackBackend):
q=[{"field": "resource_id", "op": "eq", "value": resource_id}],
)
return measures[0].counter_volume if measures else None
class VropsBackend(OpenstackBackend):
def __init__(self, vim_account: dict):
self.vrops = vROPS_Helper(
vrops_site=vim_account["config"]["vrops_site"],
vrops_user=vim_account["config"]["vrops_user"],
vrops_password=vim_account["config"]["vrops_password"],
)
def collect_metrics(self, metrics_list: List[Dict]):
# Fetch the list of all known resources from vROPS.
resource_list = self.vrops.get_vm_resource_list_from_vrops()
vdu_mappings = {}
extended_metrics = []
for metric in metrics_list:
vim_id = metric["vm_id"]
# Map the vROPS instance id to the vim-id so we can look it up.
for resource in resource_list:
for resourceIdentifier in resource["resourceKey"][
"resourceIdentifiers"
]:
if (
resourceIdentifier["identifierType"]["name"]
== "VMEntityInstanceUUID"
):
if resourceIdentifier["value"] != vim_id:
continue
vdu_mappings[vim_id] = resource["identifier"]
if vim_id in vdu_mappings:
metric["vrops_id"] = vdu_mappings[vim_id]
extended_metrics.append(metric)
if len(extended_metrics) != 0:
return self.vrops.get_metrics(extended_metrics)
else:
return []
#######################################################################################
# Copyright ETSI Contributors and Others.
#
# 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 json
import logging
import traceback
import requests
log = logging.getLogger(__name__)
# Ref: https://docs.vmware.com/en/vRealize-Operations-Manager/7.0/vrealize-operations-manager-70-reference-guide.pdf
# Potential metrics of interest
# "cpu|capacity_contentionPct"
# "cpu|corecount_provisioned"
# "cpu|costopPct"
# "cpu|demandmhz"
# "cpu|demandPct"
# "cpu|effective_limit"
# "cpu|iowaitPct"
# "cpu|readyPct"
# "cpu|swapwaitPct"
# "cpu|usage_average"
# "cpu|usagemhz_average"
# "cpu|usagemhz_average_mtd"
# "cpu|vm_capacity_provisioned"
# "cpu|workload"
# "guestfilesystem|percentage_total"
# "guestfilesystem|usage_total"
# "mem|consumedPct"
# "mem|guest_usage"
# "mem|host_contentionPct"
# "mem|reservation_used"
# "mem|swapinRate_average"
# "mem|swapoutRate_average"
# "mem|swapped_average"
# "mem|usage_average"
# "net:Aggregate of all instances|droppedPct"
# "net|broadcastTx_summation"
# "net|droppedTx_summation"
# "net|multicastTx_summation"
# "net|pnicBytesRx_average"
# "net|pnicBytesTx_average"
# "net|received_average"
# "net|transmitted_average"
# "net|usage_average"
# "virtualDisk:Aggregate of all instances|commandsAveraged_average"
# "virtualDisk:Aggregate of all instances|numberReadAveraged_average"
# "virtualDisk:Aggregate of all instances|numberWriteAveraged_average"
# "virtualDisk:Aggregate of all instances|totalLatency"
# "virtualDisk:Aggregate of all instances|totalReadLatency_average"
# "virtualDisk:Aggregate of all instances|totalWriteLatency_average"
# "virtualDisk:Aggregate of all instances|usage"
# "virtualDisk:Aggregate of all instances|vDiskOIO"
# "virtualDisk|read_average"
# "virtualDisk|write_average"
METRIC_MAPPINGS = {
# Percent guest operating system active memory.
"average_memory_utilization": "mem|usage_average",
# Percentage of CPU that was used out of all the CPU that was allocated.
"cpu_utilization": "cpu|usage_average",
# KB/s of data read in the performance interval
"disk_read_bytes": "virtualDisk|read_average",
# Average of read commands per second during the collection interval.
"disk_read_ops": "virtualDisk:aggregate of all instances|numberReadAveraged_average",
# KB/s of data written in the performance interval.
"disk_write_bytes": "virtualDisk|write_average",
# Average of write commands per second during the collection interval.
"disk_write_ops": "virtualDisk:aggregate of all instances|numberWriteAveraged_average",
# Not supported by vROPS, will always return 0.
"packets_in_dropped": "net|droppedRx_summation",
# Transmitted packets dropped in the collection interval.
"packets_out_dropped": "net|droppedTx_summation",
# Bytes received in the performance interval.
"packets_received": "net|received_average",
# Packets transmitted in the performance interval.
"packets_sent": "net|transmitted_average",
}
# If the unit from vROPS does not align with the expected value. multiply by the specified amount to ensure
# the correct unit is returned.
METRIC_MULTIPLIERS = {
"disk_read_bytes": 1024,
"disk_write_bytes": 1024,
"packets_received": 1024,
"packets_sent": 1024,
}
class vROPS_Helper:
def __init__(self, vrops_site="https://vrops", vrops_user="", vrops_password=""):
self.vrops_site = vrops_site
self.vrops_user = vrops_user
self.vrops_password = vrops_password
def get_vrops_token(self):
"""Fetches token from vrops"""
auth_url = "/suite-api/api/auth/token/acquire"
headers = {"Content-Type": "application/json", "Accept": "application/json"}
req_body = {"username": self.vrops_user, "password": self.vrops_password}
resp = requests.post(
self.vrops_site + auth_url, json=req_body, verify=False, headers=headers
)
if resp.status_code != 200:
log.error(
"Failed to get token from vROPS: {} {}".format(
resp.status_code, resp.content
)
)
return None
resp_data = json.loads(resp.content.decode("utf-8"))
return resp_data["token"]
def get_vm_resource_list_from_vrops(self):
"""Find all known resource IDs in vROPs"""
auth_token = self.get_vrops_token()
api_url = "/suite-api/api/resources?resourceKind=VirtualMachine"
headers = {
"Accept": "application/json",
"Authorization": "vRealizeOpsToken {}".format(auth_token),
}
resource_list = []
resp = requests.get(self.vrops_site + api_url, verify=False, headers=headers)
if resp.status_code != 200:
log.error(
"Failed to get resource list from vROPS: {} {}".format(
resp.status_code, resp.content
)
)
return resource_list
try:
resp_data = json.loads(resp.content.decode("utf-8"))
if resp_data.get("resourceList") is not None:
resource_list = resp_data.get("resourceList")
except Exception as exp:
log.error(
"get_vm_resource_id: Error in parsing {}\n{}".format(
exp, traceback.format_exc()
)
)
return resource_list
def get_metrics(self, metrics_list=[]):
monitoring_keys = {}
vdus = {}
# Collect the names of all the metrics we need to query
for metric in metrics_list:
metric_name = metric["metric"]
if metric_name not in METRIC_MAPPINGS:
log.debug(f"Metric {metric_name} not supported, ignoring")
continue
monitoring_keys[metric_name] = METRIC_MAPPINGS[metric_name]
vrops_id = metric["vrops_id"]
vdus[vrops_id] = 1
metrics = []
# Make a query for only the stats we have been asked for
stats_key = ""
for stat in monitoring_keys.values():
stats_key += "&statKey={}".format(stat)
# And only ask for the resource ids that we are interested in
resource_ids = ""
for key in vdus.keys():
resource_ids += "&resourceId={}".format(key)
try:
# Now we can make a single call to vROPS to collect all relevant metrics for resources we need to monitor
api_url = (
"/suite-api/api/resources/stats?IntervalType=MINUTES&IntervalCount=1"
"&rollUpType=MAX&currentOnly=true{}{}".format(stats_key, resource_ids)
)
auth_token = self.get_vrops_token()
headers = {
"Accept": "application/json",
"Authorization": "vRealizeOpsToken {}".format(auth_token),
}
resp = requests.get(
self.vrops_site + api_url, verify=False, headers=headers
)
if resp.status_code != 200:
log.error(
f"Failed to get Metrics data from vROPS for {resp.status_code} {resp.content}"
)
return []
m_data = json.loads(resp.content.decode("utf-8"))
if "values" not in m_data:
return metrics
statistics = m_data["values"]
for vdu_stat in statistics:
vrops_id = vdu_stat["resourceId"]
log.info(f"vrops_id: {vrops_id}")
for item in vdu_stat["stat-list"]["stat"]:
reported_metric = item["statKey"]["key"]
if reported_metric not in METRIC_MAPPINGS.values():
continue
# Convert the vROPS metric name back to OSM key
metric_name = list(METRIC_MAPPINGS.keys())[
list(METRIC_MAPPINGS.values()).index(reported_metric)
]
if metric_name in monitoring_keys.keys():
metric_value = item["data"][-1]
if metric_name in METRIC_MULTIPLIERS:
metric_value *= METRIC_MULTIPLIERS[metric_name]
log.info(f" {metric_name} ({reported_metric}): {metric_value}")
# Find the associated metric in requested list
for item in metrics_list:
if (
item["vrops_id"] == vrops_id
and item["metric"] == metric_name
):
metric = item
metric["value"] = metric_value
metrics.append(metric)
break
except Exception as exp:
log.error(
"Exception while parsing metrics data from vROPS {}\n{}".format(
exp, traceback.format_exc()
)
)
return metrics
......@@ -75,7 +75,7 @@ deps = {[testenv]deps}
pylint
skip_install = true
commands =
pylint -E src setup.py --disable=E0401
pylint -E src setup.py --disable=E0401 --disable=E1111
[testenv:pylint-webhook]
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment