Merge "Add scale out TCs with availability zone support"
[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 six
12
13 from yardstick.common import constants
14 from yardstick.common import utils
15
16
17 class Flags(object):
18     """Class to represent the status of the flags in a context"""
19
20     _FLAGS = {'no_setup': False,
21               'no_teardown': False,
22               'os_cloud_config': constants.OS_CLOUD_DEFAULT_CONFIG}
23
24     def __init__(self, **kwargs):
25         for name, value in self._FLAGS.items():
26             setattr(self, name, value)
27
28         for name, value in ((name, value) for (name, value) in kwargs.items()
29                             if name in self._FLAGS):
30             setattr(self, name, value)
31
32     def parse(self, **kwargs):
33         """Read in values matching the flags stored in this object"""
34         if not kwargs:
35             return
36
37         for name, value in ((name, value) for (name, value) in kwargs.items()
38                             if name in self._FLAGS):
39             setattr(self, name, value)
40
41
42 @six.add_metaclass(abc.ABCMeta)
43 class Context(object):
44     """Class that represents a context in the logical model"""
45     list = []
46     SHORT_TASK_ID_LEN = 8
47
48     def __init__(self, host_name_separator='.'):
49         Context.list.append(self)
50         self._flags = Flags()
51         self._name = None
52         self._task_id = None
53         self._host_name_separator = host_name_separator
54
55     def init(self, attrs):
56         """Initiate context"""
57         self._name = attrs['name']
58         self._task_id = attrs['task_id']
59         self._flags.parse(**attrs.get('flags', {}))
60         self._name_task_id = '{}-{}'.format(
61             self._name, self._task_id[:self.SHORT_TASK_ID_LEN])
62
63     def split_host_name(self, name):
64         if (isinstance(name, six.string_types)
65                 and self._host_name_separator in name):
66             return tuple(name.split(self._host_name_separator, 1))
67         return None, None
68
69     @property
70     def name(self):
71         if self._flags.no_setup or self._flags.no_teardown:
72             return self._name
73         else:
74             return self._name_task_id
75
76     @property
77     def assigned_name(self):
78         return self._name
79
80     @property
81     def host_name_separator(self):
82         return self._host_name_separator
83
84     @staticmethod
85     def get_cls(context_type):
86         """Return class of specified type."""
87         for context in utils.itersubclasses(Context):
88             if context_type == context.__context_type__:
89                 return context
90         raise RuntimeError("No such context_type %s" % context_type)
91
92     @staticmethod
93     def get(context_type):
94         """Returns instance of a context for context type.
95         """
96         return Context.get_cls(context_type)()
97
98     @abc.abstractmethod
99     def deploy(self):
100         """Deploy context."""
101
102     @abc.abstractmethod
103     def undeploy(self):
104         """Undeploy context."""
105         self._delete_context()
106
107     def _delete_context(self):
108         Context.list.remove(self)
109
110     @abc.abstractmethod
111     def _get_server(self, attr_name):
112         """get server info by name from context
113         """
114
115     @abc.abstractmethod
116     def _get_network(self, attr_name):
117         """get network info by name from context
118         """
119
120     @staticmethod
121     def get_server(attr_name):
122         """lookup server info by name from context
123         attr_name: either a name for a server created by yardstick or a dict
124         with attribute name mapping when using external heat templates
125         """
126         servers = (context._get_server(attr_name) for context in Context.list)
127         try:
128             return next(s for s in servers if s)
129         except StopIteration:
130             raise ValueError("context not found for server %r" %
131                              attr_name)
132
133     @staticmethod
134     def get_context_from_server(attr_name):
135         """lookup context info by name from node config
136         attr_name: either a name of the node created by yardstick or a dict
137         with attribute name mapping when using external templates
138
139         :returns Context instance
140         """
141         servers = ((context._get_server(attr_name), context)
142                    for context in Context.list)
143         try:
144             return next(con for s, con in servers if s)
145         except StopIteration:
146             raise ValueError("context not found for name %r" %
147                              attr_name)
148
149     @staticmethod
150     def get_network(attr_name):
151         """lookup server info by name from context
152         attr_name: either a name for a server created by yardstick or a dict
153         with attribute name mapping when using external heat templates
154         """
155
156         networks = (context._get_network(attr_name) for context in Context.list)
157         try:
158             return next(n for n in networks if n)
159         except StopIteration:
160             raise ValueError("context not found for server %r" %
161                              attr_name)