aboutsummaryrefslogtreecommitdiffstats
path: root/yardstick/common
diff options
context:
space:
mode:
Diffstat (limited to 'yardstick/common')
-rw-r--r--yardstick/common/constants.py4
-rw-r--r--yardstick/common/exceptions.py42
-rw-r--r--yardstick/common/kubernetes_utils.py86
-rw-r--r--yardstick/common/messaging/__init__.py27
-rw-r--r--yardstick/common/messaging/consumer.py10
-rw-r--r--yardstick/common/messaging/payloads.py20
-rw-r--r--yardstick/common/messaging/producer.py13
-rw-r--r--yardstick/common/utils.py22
8 files changed, 197 insertions, 27 deletions
diff --git a/yardstick/common/constants.py b/yardstick/common/constants.py
index 1ebd32509..2f14d4bc4 100644
--- a/yardstick/common/constants.py
+++ b/yardstick/common/constants.py
@@ -171,3 +171,7 @@ TESTSUITE_PRE = 'opnfv_'
# OpenStack cloud default config parameters
OS_CLOUD_DEFAULT_CONFIG = {'verify': False}
+
+# Kubernetes
+SCOPE_NAMESPACED = 'Namespaced'
+SCOPE_CLUSTER = 'Cluster'
diff --git a/yardstick/common/exceptions.py b/yardstick/common/exceptions.py
index 935c77866..641c4e1c4 100644
--- a/yardstick/common/exceptions.py
+++ b/yardstick/common/exceptions.py
@@ -14,6 +14,8 @@
from oslo_utils import excutils
+from yardstick.common import constants
+
class ProcessExecutionError(RuntimeError):
def __init__(self, message, returncode):
@@ -191,6 +193,15 @@ class TaskRenderError(YardstickException):
message = 'Failed to render template:\n%(input_task)s'
+class RunnerIterationIPCSetupActionNeeded(YardstickException):
+ message = ('IterationIPC needs the "setup" action to retrieve the VNF '
+ 'handling processes PIDs to receive the messages sent')
+
+
+class RunnerIterationIPCNoCtxs(YardstickException):
+ message = 'Benchmark "setup" action did not return any VNF process PID'
+
+
class TimerTimeout(YardstickException):
message = 'Timer timeout expired, %(timeout)s seconds'
@@ -199,10 +210,41 @@ class WaitTimeout(YardstickException):
message = 'Wait timeout while waiting for condition'
+class KubernetesApiException(YardstickException):
+ message = ('Kubernetes API errors. Action: %(action)s, '
+ 'resource: %(resource)s')
+
+
+class KubernetesConfigFileNotFound(YardstickException):
+ message = 'Config file (%s) not found' % constants.K8S_CONF_FILE
+
+
class KubernetesTemplateInvalidVolumeType(YardstickException):
message = 'No valid "volume" types present in %(volume)s'
+class KubernetesCRDObjectDefinitionError(YardstickException):
+ message = ('Kubernetes Custom Resource Definition Object error, missing '
+ 'parameters: %(missing_parameters)s')
+
+
+class KubernetesNetworkObjectDefinitionError(YardstickException):
+ message = ('Kubernetes Network object definition error, missing '
+ 'parameters: %(missing_parameters)s')
+
+
+class KubernetesNetworkObjectKindMissing(YardstickException):
+ message = 'Kubernetes kind "Network" is not defined'
+
+
+class KubernetesWrongRestartPolicy(YardstickException):
+ message = 'Restart policy "%(rpolicy)s" is not valid'
+
+
+class KubernetesContainerPortNotDefined(YardstickException):
+ message = 'Container port not defined in "%(port)s"'
+
+
class ScenarioCreateNetworkError(YardstickException):
message = 'Create Neutron Network Scenario failed'
diff --git a/yardstick/common/kubernetes_utils.py b/yardstick/common/kubernetes_utils.py
index ee8e8edcd..42267fc41 100644
--- a/yardstick/common/kubernetes_utils.py
+++ b/yardstick/common/kubernetes_utils.py
@@ -13,6 +13,8 @@ from kubernetes import config
from kubernetes.client.rest import ApiException
from yardstick.common import constants as consts
+from yardstick.common import exceptions
+
LOG = logging.getLogger(__name__)
LOG.setLevel(logging.DEBUG)
@@ -22,12 +24,26 @@ def get_core_api(): # pragma: no cover
try:
config.load_kube_config(config_file=consts.K8S_CONF_FILE)
except IOError:
- LOG.exception('config file not found')
- raise
-
+ raise exceptions.KubernetesConfigFileNotFound()
return client.CoreV1Api()
+def get_extensions_v1beta_api():
+ try:
+ config.load_kube_config(config_file=consts.K8S_CONF_FILE)
+ except IOError:
+ raise exceptions.KubernetesConfigFileNotFound()
+ return client.ApiextensionsV1beta1Api()
+
+
+def get_custom_objects_api():
+ try:
+ config.load_kube_config(config_file=consts.K8S_CONF_FILE)
+ except IOError:
+ raise exceptions.KubernetesConfigFileNotFound()
+ return client.CustomObjectsApi()
+
+
def get_node_list(**kwargs): # pragma: no cover
core_v1_api = get_core_api()
try:
@@ -187,6 +203,70 @@ def delete_config_map(name,
raise
+def create_custom_resource_definition(body):
+ api = get_extensions_v1beta_api()
+ body_obj = client.V1beta1CustomResourceDefinition(
+ spec=body['spec'], metadata=body['metadata'])
+ try:
+ api.create_custom_resource_definition(body_obj)
+ except ValueError:
+ # NOTE(ralonsoh): bug in kubernetes-client/python 6.0.0
+ # https://github.com/kubernetes-client/python/issues/491
+ pass
+ except ApiException:
+ raise exceptions.KubernetesApiException(
+ action='create', resource='CustomResourceDefinition')
+
+
+def delete_custom_resource_definition(name):
+ api = get_extensions_v1beta_api()
+ body_obj = client.V1DeleteOptions()
+ try:
+ api.delete_custom_resource_definition(name, body_obj)
+ except ApiException:
+ raise exceptions.KubernetesApiException(
+ action='delete', resource='CustomResourceDefinition')
+
+
+def get_custom_resource_definition(kind):
+ api = get_extensions_v1beta_api()
+ try:
+ crd_list = api.list_custom_resource_definition()
+ for crd_obj in (crd_obj for crd_obj in crd_list.items
+ if crd_obj.spec.names.kind == kind):
+ return crd_obj
+ return None
+ except ApiException:
+ raise exceptions.KubernetesApiException(
+ action='delete', resource='CustomResourceDefinition')
+
+
+def create_network(scope, group, version, plural, body, namespace='default'):
+ api = get_custom_objects_api()
+ try:
+ if scope == consts.SCOPE_CLUSTER:
+ api.create_cluster_custom_object(group, version, plural, body)
+ else:
+ api.create_namespaced_custom_object(
+ group, version, namespace, plural, body)
+ except ApiException:
+ raise exceptions.KubernetesApiException(
+ action='create', resource='Custom Object: Network')
+
+
+def delete_network(scope, group, version, plural, name, namespace='default'):
+ api = get_custom_objects_api()
+ try:
+ if scope == consts.SCOPE_CLUSTER:
+ api.delete_cluster_custom_object(group, version, plural, name, {})
+ else:
+ api.delete_namespaced_custom_object(
+ group, version, namespace, plural, name, {})
+ except ApiException:
+ raise exceptions.KubernetesApiException(
+ action='delete', resource='Custom Object: Network')
+
+
def get_pod_list(namespace='default'): # pragma: no cover
core_v1_api = get_core_api()
try:
diff --git a/yardstick/common/messaging/__init__.py b/yardstick/common/messaging/__init__.py
index f0f012ec3..bd700d9b1 100644
--- a/yardstick/common/messaging/__init__.py
+++ b/yardstick/common/messaging/__init__.py
@@ -1,14 +1,3 @@
-# Copyright (c) 2018 Intel Corporation
-#
-# 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.
@@ -28,9 +17,17 @@ TRANSPORT_URL = (MQ_SERVICE + '://' + MQ_USER + ':' + MQ_PASS + '@' + SERVER +
RPC_SERVER_EXECUTOR = 'threading'
# Topics.
-RUNNER = 'runner'
+TOPIC_TG = 'topic_traffic_generator'
+TOPIC_RUNNER = 'topic_runner'
# Methods.
-# RUNNER methods:
-RUNNER_INFO = 'runner_info'
-RUNNER_LOOP = 'runner_loop'
+# Traffic generator consumers methods. Names must match the methods implemented
+# in the consumer endpoint class.
+TG_METHOD_STARTED = 'tg_method_started'
+TG_METHOD_FINISHED = 'tg_method_finished'
+TG_METHOD_ITERATION = 'tg_method_iteration'
+
+# Runner consumers methods. Names must match the methods implemented in the
+# consumer endpoint class.
+RUNNER_METHOD_START_ITERATION = "runner_method_start_iteration"
+RUNNER_METHOD_STOP_ITERATION = "runner_method_stop_iteration"
diff --git a/yardstick/common/messaging/consumer.py b/yardstick/common/messaging/consumer.py
index 24ec6f184..c99d7ed27 100644
--- a/yardstick/common/messaging/consumer.py
+++ b/yardstick/common/messaging/consumer.py
@@ -29,9 +29,9 @@ LOG = logging.getLogger(__name__)
class NotificationHandler(object):
"""Abstract class to define a endpoint object for a MessagingConsumer"""
- def __init__(self, _id, ctx_pids, queue):
+ def __init__(self, _id, ctx_ids, queue):
self._id = _id
- self._ctx_pids = ctx_pids
+ self._ctx_ids = ctx_ids
self._queue = queue
@@ -43,11 +43,11 @@ class MessagingConsumer(object):
the messages published by a `MessagingNotifier`.
"""
- def __init__(self, topic, pids, endpoints, fanout=True):
+ def __init__(self, topic, ids, endpoints, fanout=True):
"""Init function.
:param topic: (string) MQ exchange topic
- :param pids: (list of int) list of PIDs of the processes implementing
+ :param ids: (list of int) list of IDs of the processes implementing
the MQ Notifier which will be in the message context
:param endpoints: (list of class) list of classes implementing the
methods (see `MessagingNotifier.send_message) used by
@@ -58,7 +58,7 @@ class MessagingConsumer(object):
:returns: `MessagingConsumer` class object
"""
- self._pids = pids
+ self._ids = ids
self._endpoints = endpoints
self._transport = oslo_messaging.get_rpc_transport(
cfg.CONF, url=messaging.TRANSPORT_URL)
diff --git a/yardstick/common/messaging/payloads.py b/yardstick/common/messaging/payloads.py
index d29d79808..8ede1e58e 100644
--- a/yardstick/common/messaging/payloads.py
+++ b/yardstick/common/messaging/payloads.py
@@ -51,3 +51,23 @@ class Payload(object):
def dict_to_obj(cls, _dict):
"""Returns a Payload object built from the dictionary elements"""
return cls(**_dict)
+
+
+class TrafficGeneratorPayload(Payload):
+ """Base traffic generator payload class"""
+ REQUIRED_FIELDS = {
+ 'version', # (str) version of the payload transmitted.
+ 'iteration', # (int) iteration index during the traffic injection,
+ # starting from 1.
+ 'kpi' # (dict) collection of KPIs collected from the traffic
+ # injection. The content will depend on the generator and the
+ # traffic type.
+ }
+
+
+class RunnerPayload(Payload):
+ """Base runner payload class"""
+ REQUIRED_FIELDS = {
+ 'version', # (str) version of the payload transmitted.
+ 'data' # (dict) generic container of data to be used if needed.
+ }
diff --git a/yardstick/common/messaging/producer.py b/yardstick/common/messaging/producer.py
index b6adc0c17..aadab649d 100644
--- a/yardstick/common/messaging/producer.py
+++ b/yardstick/common/messaging/producer.py
@@ -34,18 +34,18 @@ class MessagingProducer(object):
messages in a message queue.
"""
- def __init__(self, topic, pid=os.getpid(), fanout=True):
+ def __init__(self, topic, _id=os.getpid(), fanout=True):
"""Init function.
:param topic: (string) MQ exchange topic
- :param pid: (int) PID of the process implementing this MQ Notifier
+ :param id: (int) ID of the process implementing this MQ Notifier
:param fanout: (bool) MQ clients may request that a copy of the message
be delivered to all servers listening on a topic by
setting fanout to ``True``, rather than just one of them
:returns: `MessagingNotifier` class object
"""
self._topic = topic
- self._pid = pid
+ self._id = _id
self._fanout = fanout
self._transport = oslo_messaging.get_rpc_transport(
cfg.CONF, url=messaging.TRANSPORT_URL)
@@ -65,6 +65,11 @@ class MessagingProducer(object):
consumer endpoints
:param payload: (subclass `Payload`) payload content
"""
- self._notifier.cast({'pid': self._pid},
+ self._notifier.cast({'id': self._id},
method,
**payload.obj_to_dict())
+
+ @property
+ def id(self):
+ """Return MQ producer ID"""
+ return self._id
diff --git a/yardstick/common/utils.py b/yardstick/common/utils.py
index f9fe0e336..85cecc714 100644
--- a/yardstick/common/utils.py
+++ b/yardstick/common/utils.py
@@ -527,3 +527,25 @@ def wait_until_true(predicate, timeout=60, sleep=1, exception=None):
if exception and issubclass(exception, Exception):
raise exception # pylint: disable=raising-bad-type
raise exceptions.WaitTimeout
+
+
+def send_socket_command(host, port, command):
+ """Send a string command to a specific port in a host
+
+ :param host: (str) ip or hostname of the host
+ :param port: (int) port number
+ :param command: (str) command to send
+ :return: 0 if success, error number if error
+ """
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ ret = 0
+ try:
+ err_number = sock.connect_ex((host, int(port)))
+ if err_number != 0:
+ return err_number
+ sock.sendall(six.b(command))
+ except Exception: # pylint: disable=broad-except
+ ret = 1
+ finally:
+ sock.close()
+ return ret