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