Add "IterationIPC" runner
[yardstick.git] / yardstick / benchmark / contexts / base.py
1 ##############################################################################
2 # Copyright (c) 2015 Huawei Technologies Co.,Ltd and others.
3 #
4 # All rights reserved. This program and the accompanying materials
5 # are made available under the terms of the Apache License, Version 2.0
6 # which accompanies this distribution, and is available at
7 # http://www.apache.org/licenses/LICENSE-2.0
8 ##############################################################################
9
10 import abc
11 import errno
12 import six
13 import os
14
15 from yardstick.common import constants
16 from yardstick.common import utils
17 from yardstick.common.constants import YARDSTICK_ROOT_PATH
18
19
20 class Flags(object):
21     """Class to represent the status of the flags in a context"""
22
23     _FLAGS = {'no_setup': False,
24               'no_teardown': False,
25               'os_cloud_config': constants.OS_CLOUD_DEFAULT_CONFIG}
26
27     def __init__(self, **kwargs):
28         for name, value in self._FLAGS.items():
29             setattr(self, name, value)
30
31         for name, value in ((name, value) for (name, value) in kwargs.items()
32                             if name in self._FLAGS):
33             setattr(self, name, value)
34
35     def parse(self, **kwargs):
36         """Read in values matching the flags stored in this object"""
37         if not kwargs:
38             return
39
40         for name, value in ((name, value) for (name, value) in kwargs.items()
41                             if name in self._FLAGS):
42             setattr(self, name, value)
43
44
45 @six.add_metaclass(abc.ABCMeta)
46 class Context(object):
47     """Class that represents a context in the logical model"""
48     list = []
49     SHORT_TASK_ID_LEN = 8
50
51     def __init__(self, host_name_separator='.'):
52         Context.list.append(self)
53         self._flags = Flags()
54         self._name = None
55         self._task_id = None
56         self.file_path = None
57         self._host_name_separator = host_name_separator
58
59     def init(self, attrs):
60         """Initiate context"""
61         self._name = attrs['name']
62         self._task_id = attrs['task_id']
63         self._flags.parse(**attrs.get('flags', {}))
64         self._name_task_id = '{}-{}'.format(
65             self._name, self._task_id[:self.SHORT_TASK_ID_LEN])
66
67     def split_host_name(self, name):
68         if (isinstance(name, six.string_types)
69                 and self._host_name_separator in name):
70             return tuple(name.split(self._host_name_separator, 1))
71         return None, None
72
73     def read_pod_file(self, attrs):
74         self.file_path = file_path = attrs.get("file", "pod.yaml")
75         try:
76             cfg = utils.read_yaml_file(self.file_path)
77         except IOError as io_error:
78             if io_error.errno != errno.ENOENT:
79                 raise
80
81             self.file_path = os.path.join(YARDSTICK_ROOT_PATH, file_path)
82             cfg = utils.read_yaml_file(self.file_path)
83
84         for node in cfg["nodes"]:
85             node["ctx_type"] = self.__context_type__
86
87         self.nodes.extend(cfg["nodes"])
88         self.controllers.extend([node for node in cfg["nodes"]
89                                  if node.get("role") == "Controller"])
90         self.computes.extend([node for node in cfg["nodes"]
91                               if node.get("role") == "Compute"])
92         self.baremetals.extend([node for node in cfg["nodes"]
93                                 if node.get("role") == "Baremetal"])
94         return cfg
95
96     @property
97     def name(self):
98         if self._flags.no_setup or self._flags.no_teardown:
99             return self._name
100         else:
101             return self._name_task_id
102
103     @property
104     def assigned_name(self):
105         return self._name
106
107     @property
108     def host_name_separator(self):
109         return self._host_name_separator
110
111     @staticmethod
112     def get_cls(context_type):
113         """Return class of specified type."""
114         for context in utils.itersubclasses(Context):
115             if context_type == context.__context_type__:
116                 return context
117         raise RuntimeError("No such context_type %s" % context_type)
118
119     @staticmethod
120     def get(context_type):
121         """Returns instance of a context for context type.
122         """
123         return Context.get_cls(context_type)()
124
125     @abc.abstractmethod
126     def deploy(self):
127         """Deploy context."""
128
129     @abc.abstractmethod
130     def undeploy(self):
131         """Undeploy context."""
132         self._delete_context()
133
134     def _delete_context(self):
135         Context.list.remove(self)
136
137     @abc.abstractmethod
138     def _get_server(self, attr_name):
139         """get server info by name from context
140         """
141
142     @abc.abstractmethod
143     def _get_network(self, attr_name):
144         """get network info by name from context
145         """
146
147     @staticmethod
148     def get_server(attr_name):
149         """lookup server info by name from context
150         attr_name: either a name for a server created by yardstick or a dict
151         with attribute name mapping when using external heat templates
152         """
153         servers = (context._get_server(attr_name) for context in Context.list)
154         try:
155             return next(s for s in servers if s)
156         except StopIteration:
157             raise ValueError("context not found for server %r" %
158                              attr_name)
159
160     @staticmethod
161     def get_physical_nodes():
162         """return physical node names for all contexts"""
163         physical_nodes = {}
164         for context in Context.list:
165             nodes = context._get_physical_nodes()
166             physical_nodes.update({context._name: nodes})
167
168         return physical_nodes
169
170     @staticmethod
171     def get_physical_node_from_server(server_name):
172         """return physical nodes for all contexts"""
173         context = Context.get_context_from_server(server_name)
174         if context == None:
175             return  None
176
177         return context._get_physical_node_for_server(server_name)
178
179     @staticmethod
180     def get_context_from_server(attr_name):
181         """lookup context info by name from node config
182         attr_name: either a name of the node created by yardstick or a dict
183         with attribute name mapping when using external templates
184
185         :returns Context instance
186         """
187         servers = ((context._get_server(attr_name), context)
188                    for context in Context.list)
189         try:
190             return next(con for s, con in servers if s)
191         except StopIteration:
192             raise ValueError("context not found for name %r" %
193                              attr_name)
194
195     @staticmethod
196     def get_network(attr_name):
197         """lookup server info by name from context
198         attr_name: either a name for a server created by yardstick or a dict
199         with attribute name mapping when using external heat templates
200         """
201
202         networks = (context._get_network(attr_name) for context in Context.list)
203         try:
204             return next(n for n in networks if n)
205         except StopIteration:
206             raise ValueError("context not found for server %r" %
207                              attr_name)
208
209     @abc.abstractmethod
210     def _get_physical_nodes(self):
211         """return the list of physical nodes in context"""
212
213     @abc.abstractmethod
214     def _get_physical_node_for_server(self, server_name):
215         """ Find physical node for given server
216
217         :param server_name: (string) Server name in scenario
218         :return string:  <node_name>.<context_name>
219         """