7aab469424bdb5ec7e3f810942bc707cb6201e7c
[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:
85                 try_append_module(module_name, sys.modules)
86             except ImportError:
87                 logger.exception("unable to import %s", module_name)
88
89
90 def parse_yaml(file_path):
91     try:
92         with open(file_path) as f:
93             value = yaml.safe_load(f)
94     except IOError:
95         return {}
96     except OSError as e:
97         if e.errno != errno.EEXIST:
98             raise
99     else:
100         return value
101
102
103 def get_param(key, default=''):
104
105     conf_file = os.environ.get('CONF_FILE', '/etc/yardstick/yardstick.yaml')
106
107     conf = parse_yaml(conf_file)
108     try:
109         return reduce(lambda a, b: a[b], key.split('.'), conf)
110     except KeyError:
111         if not default:
112             raise
113         return default
114
115
116 def makedirs(d):
117     try:
118         os.makedirs(d)
119     except OSError as e:
120         if e.errno != errno.EEXIST:
121             raise
122
123
124 def execute_command(cmd):
125     exec_msg = "Executing command: '%s'" % cmd
126     logger.debug(exec_msg)
127
128     output = subprocess.check_output(cmd.split()).split(os.linesep)
129
130     return output
131
132
133 def source_env(env_file):
134     p = subprocess.Popen(". %s; env" % env_file, stdout=subprocess.PIPE,
135                          shell=True)
136     output = p.communicate()[0]
137     env = dict((line.split('=', 1) for line in output.splitlines()))
138     os.environ.update(env)
139     return env
140
141
142 def read_json_from_file(path):
143     with open(path, 'r') as f:
144         j = f.read()
145     # don't use jsonutils.load() it conflicts with already decoded input
146     return jsonutils.loads(j)
147
148
149 def write_json_to_file(path, data, mode='w'):
150     with open(path, mode) as f:
151         jsonutils.dump(data, f)
152
153
154 def write_file(path, data, mode='w'):
155     with open(path, mode) as f:
156         f.write(data)
157
158
159 def parse_ini_file(path):
160     parser = configparser.ConfigParser()
161     parser.read(path)
162
163     try:
164         default = {k: v for k, v in parser.items('DEFAULT')}
165     except configparser.NoSectionError:
166         default = {}
167
168     config = dict(DEFAULT=default,
169                   **{s: {k: v for k, v in parser.items(
170                       s)} for s in parser.sections()})
171
172     return config
173
174
175 def get_port_mac(sshclient, port):
176     cmd = "ifconfig |grep HWaddr |grep %s |awk '{print $5}' " % port
177     status, stdout, stderr = sshclient.execute(cmd)
178
179     if status:
180         raise RuntimeError(stderr)
181     return stdout.rstrip()
182
183
184 def get_port_ip(sshclient, port):
185     cmd = "ifconfig %s |grep 'inet addr' |awk '{print $2}' " \
186         "|cut -d ':' -f2 " % port
187     status, stdout, stderr = sshclient.execute(cmd)
188
189     if status:
190         raise RuntimeError(stderr)
191     return stdout.rstrip()