Merge "Extend TC008 to run pktgen-dpdk inside VM Need a fast path inside VM to verify...
[yardstick.git] / yardstick / common / utils.py
1 # Copyright 2013: Mirantis Inc.
2 # All Rights Reserved.
3 #
4 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
5 #    not use this file except in compliance with the License. You may obtain
6 #    a copy of the License at
7 #
8 #         http://www.apache.org/licenses/LICENSE-2.0
9 #
10 #    Unless required by applicable law or agreed to in writing, software
11 #    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 #    License for the specific language governing permissions and limitations
14 #    under the License.
15
16 # yardstick comment: this is a modified copy of rally/rally/common/utils.py
17
18 from __future__ import absolute_import
19 from __future__ import print_function
20
21 import errno
22 import logging
23 import os
24 import subprocess
25 import sys
26 from functools import reduce
27
28 import yaml
29 from six.moves import configparser
30 from oslo_utils import importutils
31 from oslo_serialization import jsonutils
32
33 import yardstick
34
35 logger = logging.getLogger(__name__)
36 logger.setLevel(logging.DEBUG)
37
38
39 # Decorator for cli-args
40 def cliargs(*args, **kwargs):
41     def _decorator(func):
42         func.__dict__.setdefault('arguments', []).insert(0, (args, kwargs))
43         return func
44     return _decorator
45
46
47 def itersubclasses(cls, _seen=None):
48     """Generator over all subclasses of a given class in depth first order."""
49
50     if not isinstance(cls, type):
51         raise TypeError("itersubclasses must be called with "
52                         "new-style classes, not %.100r" % cls)
53     _seen = _seen or set()
54     try:
55         subs = cls.__subclasses__()
56     except TypeError:   # fails only when cls is type
57         subs = cls.__subclasses__(cls)
58     for sub in subs:
59         if sub not in _seen:
60             _seen.add(sub)
61             yield sub
62             for sub in itersubclasses(sub, _seen):
63                 yield sub
64
65
66 def try_append_module(name, modules):
67     if name not in modules:
68         modules[name] = importutils.import_module(name)
69
70
71 def import_modules_from_package(package):
72     """Import modules from package and append into sys.modules
73
74     :param: package - Full package name. For example: rally.deploy.engines
75     """
76     path = [os.path.dirname(yardstick.__file__), ".."] + package.split(".")
77     path = os.path.join(*path)
78     for root, dirs, files in os.walk(path):
79         for filename in files:
80             if filename.startswith("__") or not filename.endswith(".py"):
81                 continue
82             new_package = ".".join(root.split(os.sep)).split("....")[1]
83             module_name = "%s.%s" % (new_package, filename[:-3])
84             try_append_module(module_name, sys.modules)
85
86
87 def parse_yaml(file_path):
88     try:
89         with open(file_path) as f:
90             value = yaml.safe_load(f)
91     except IOError:
92         return {}
93     except OSError as e:
94         if e.errno != errno.EEXIST:
95             raise
96     else:
97         return value
98
99
100 def get_param(key, default=''):
101
102     conf_file = os.environ.get('CONF_FILE', '/etc/yardstick/yardstick.yaml')
103
104     conf = parse_yaml(conf_file)
105     try:
106         return reduce(lambda a, b: a[b], key.split('.'), conf)
107     except KeyError:
108         if not default:
109             raise
110         return default
111
112
113 def makedirs(d):
114     try:
115         os.makedirs(d)
116     except OSError as e:
117         if e.errno != errno.EEXIST:
118             raise
119
120
121 def execute_command(cmd):
122     exec_msg = "Executing command: '%s'" % cmd
123     logger.debug(exec_msg)
124
125     output = subprocess.check_output(cmd.split()).split(os.linesep)
126
127     return output
128
129
130 def source_env(env_file):
131     p = subprocess.Popen(". %s; env" % env_file, stdout=subprocess.PIPE,
132                          shell=True)
133     output = p.communicate()[0]
134     env = dict((line.split('=', 1) for line in output.splitlines()))
135     os.environ.update(env)
136     return env
137
138
139 def read_json_from_file(path):
140     with open(path, 'r') as f:
141         j = f.read()
142     # don't use jsonutils.load() it conflicts with already decoded input
143     return jsonutils.loads(j)
144
145
146 def write_json_to_file(path, data, mode='w'):
147     with open(path, mode) as f:
148         jsonutils.dump(data, f)
149
150
151 def write_file(path, data, mode='w'):
152     with open(path, mode) as f:
153         f.write(data)
154
155
156 def parse_ini_file(path):
157     parser = configparser.ConfigParser()
158     parser.read(path)
159
160     try:
161         default = {k: v for k, v in parser.items('DEFAULT')}
162     except configparser.NoSectionError:
163         default = {}
164
165     config = dict(DEFAULT=default,
166                   **{s: {k: v for k, v in parser.items(
167                       s)} for s in parser.sections()})
168
169     return config
170
171
172 def get_port_mac(sshclient, port):
173     cmd = "ifconfig |grep HWaddr |grep %s |awk '{print $5}' " % port
174     status, stdout, stderr = sshclient.execute(cmd)
175
176     if status:
177         raise RuntimeError(stderr)
178     return stdout.rstrip()
179
180
181 def get_port_ip(sshclient, port):
182     cmd = "ifconfig %s |grep 'inet addr' |awk '{print $2}' " \
183         "|cut -d ':' -f2 " % port
184     status, stdout, stderr = sshclient.execute(cmd)
185
186     if status:
187         raise RuntimeError(stderr)
188     return stdout.rstrip()