Fix execute_command function to show all the output
[functest.git] / utils / functest_utils.py
1 #!/usr/bin/env python
2 #
3 # jose.lausuch@ericsson.com
4 # valentin.boucher@orange.com
5 # All rights reserved. This program and the accompanying materials
6 # are made available under the terms of the Apache License, Version 2.0
7 # which accompanies this distribution, and is available at
8 # http://www.apache.org/licenses/LICENSE-2.0
9 #
10
11 """ global variables """
12
13 from datetime import datetime as dt
14 import json
15 import os
16 import os.path
17 import re
18 import shutil
19 import socket
20 import subprocess
21 import sys
22 import urllib2
23
24 import functest.ci.tier_builder as tb
25 from git import Repo
26 import requests
27 import yaml
28
29
30 REPOS_DIR = os.getenv('repos_dir')
31 FUNCTEST_REPO = ("%s/functest/" % REPOS_DIR)
32
33
34 # ----------------------------------------------------------
35 #
36 #               INTERNET UTILS
37 #
38 # -----------------------------------------------------------
39 def check_internet_connectivity(url='http://www.opnfv.org/'):
40     """
41     Check if there is access to the internet
42     """
43     try:
44         urllib2.urlopen(url, timeout=5)
45         return True
46     except urllib2.URLError:
47         return False
48
49
50 def download_url(url, dest_path):
51     """
52     Download a file to a destination path given a URL
53     """
54     name = url.rsplit('/')[-1]
55     dest = dest_path + "/" + name
56     try:
57         response = urllib2.urlopen(url)
58     except (urllib2.HTTPError, urllib2.URLError):
59         return False
60
61     with open(dest, 'wb') as f:
62         shutil.copyfileobj(response, f)
63     return True
64
65
66 # ----------------------------------------------------------
67 #
68 #               CI UTILS
69 #
70 # -----------------------------------------------------------
71 def get_git_branch(repo_path):
72     """
73     Get git branch name
74     """
75     repo = Repo(repo_path)
76     branch = repo.active_branch
77     return branch.name
78
79
80 def get_installer_type(logger=None):
81     """
82     Get installer type (fuel, apex, joid, compass)
83     """
84     try:
85         installer = os.environ['INSTALLER_TYPE']
86     except KeyError:
87         if logger:
88             logger.error("Impossible to retrieve the installer type")
89         installer = "Unknown_installer"
90
91     return installer
92
93
94 def get_scenario(logger=None):
95     """
96     Get scenario
97     """
98     try:
99         scenario = os.environ['DEPLOY_SCENARIO']
100     except KeyError:
101         if logger:
102             logger.error("Impossible to retrieve the scenario")
103         scenario = "Unknown_scenario"
104
105     return scenario
106
107
108 def get_version(logger=None):
109     """
110     Get version
111     """
112     # Use the build tag to retrieve the version
113     # By default version is unknown
114     # if launched through CI the build tag has the following format
115     # jenkins-<project>-<installer>-<pod>-<job>-<branch>-<id>
116     # e.g. jenkins-functest-fuel-opnfv-jump-2-daily-master-190
117     # use regex to match branch info
118     rule = "daily-(.+?)-[0-9]*"
119     build_tag = get_build_tag(logger)
120     m = re.search(rule, build_tag)
121     if m:
122         return m.group(1)
123     else:
124         return "unknown"
125
126
127 def get_pod_name(logger=None):
128     """
129     Get PoD Name from env variable NODE_NAME
130     """
131     try:
132         return os.environ['NODE_NAME']
133     except KeyError:
134         if logger:
135             logger.error(
136                 "Unable to retrieve the POD name from environment. " +
137                 "Using pod name 'unknown-pod'")
138         return "unknown-pod"
139
140
141 def get_build_tag(logger=None):
142     """
143     Get build tag of jenkins jobs
144     """
145     try:
146         build_tag = os.environ['BUILD_TAG']
147     except KeyError:
148         if logger:
149             logger.error("Impossible to retrieve the build tag")
150         build_tag = "unknown_build_tag"
151
152     return build_tag
153
154
155 def get_db_url(logger=None):
156     """
157     Returns DB URL
158     """
159     with open(os.environ["CONFIG_FUNCTEST_YAML"]) as f:
160         functest_yaml = yaml.safe_load(f)
161     f.close()
162     db_url = functest_yaml.get("results").get("test_db_url")
163     return db_url
164
165
166 def push_results_to_db(project, case_name, logger,
167                        start_date, stop_date, criteria, details):
168     """
169     POST results to the Result target DB
170     """
171     # Retrieve params from CI and conf
172     url = get_db_url(logger) + "/results"
173     installer = get_installer_type(logger)
174     scenario = get_scenario(logger)
175     version = get_version(logger)
176     pod_name = get_pod_name(logger)
177     build_tag = get_build_tag(logger)
178     test_start = dt.fromtimestamp(start_date).strftime('%Y-%m-%d %H:%M:%S')
179     test_stop = dt.fromtimestamp(stop_date).strftime('%Y-%m-%d %H:%M:%S')
180
181     params = {"project_name": project, "case_name": case_name,
182               "pod_name": pod_name, "installer": installer,
183               "version": version, "scenario": scenario, "criteria": criteria,
184               "build_tag": build_tag, "start_date": test_start,
185               "stop_date": test_stop, "details": details}
186
187     headers = {'Content-Type': 'application/json'}
188     try:
189         r = requests.post(url, data=json.dumps(params), headers=headers)
190         if logger:
191             logger.debug(r)
192         return True
193     except Exception, e:
194         print ("Error [push_results_to_db('%s', '%s', '%s', " +
195                "'%s', '%s', '%s', '%s', '%s', '%s')]:" %
196                (url, project, case_name, pod_name, version,
197                 scenario, criteria, build_tag, details)), e
198         return False
199
200
201 def get_resolvconf_ns():
202     """
203     Get nameservers from current resolv.conf
204     """
205     nameservers = []
206     rconf = open("/etc/resolv.conf", "r")
207     line = rconf.readline()
208     while line:
209         ip = re.search(r"\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}\b", line)
210         sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
211         if ip:
212             result = sock.connect_ex((ip.group(), 53))
213             if result == 0:
214                 nameservers.append(ip.group())
215         line = rconf.readline()
216     return nameservers
217
218
219 def get_ci_envvars():
220     """
221     Get the CI env variables
222     """
223     ci_env_var = {
224         "installer": os.environ.get('INSTALLER_TYPE'),
225         "scenario": os.environ.get('DEPLOY_SCENARIO')}
226     return ci_env_var
227
228
229 def execute_command(cmd, logger=None,
230                     exit_on_error=True,
231                     info=False,
232                     error_msg="",
233                     verbose=True):
234     if not error_msg:
235         error_msg = ("The command '%s' failed." % cmd)
236     msg_exec = ("Executing command: '%s'" % cmd)
237     if verbose:
238         if logger:
239             if info:
240                 logger.info(msg_exec)
241             else:
242                 logger.debug(msg_exec)
243         else:
244             print(msg_exec)
245     p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)
246     for line in iter(p.stdout.readline, b''):
247         line = line.replace('\n', '')
248         if logger:
249             if info:
250                 logger.info(line)
251             else:
252                 logger.debug(line)
253         else:
254             print line
255     p.stdout.close()
256     returncode = p.wait()
257     if returncode != 0:
258         if verbose:
259             if logger:
260                 logger.error(error_msg)
261             else:
262                 print(error_msg)
263         if exit_on_error:
264             sys.exit(1)
265
266     return returncode
267
268
269 def get_deployment_dir(logger=None):
270     """
271     Returns current Rally deployment directory
272     """
273     with open(os.environ["CONFIG_FUNCTEST_YAML"]) as f:
274         functest_yaml = yaml.safe_load(f)
275     f.close()
276     deployment_name = functest_yaml.get("rally").get("deployment_name")
277     rally_dir = functest_yaml.get("general").get("directories").get(
278         "dir_rally_inst")
279     cmd = ("rally deployment list | awk '/" + deployment_name +
280            "/ {print $2}'")
281     p = subprocess.Popen(cmd, shell=True,
282                          stdout=subprocess.PIPE,
283                          stderr=subprocess.STDOUT)
284     deployment_uuid = p.stdout.readline().rstrip()
285     if deployment_uuid == "":
286         if logger:
287             logger.error("Rally deployment not found.")
288         exit(-1)
289     deployment_dir = (rally_dir + "/tempest/for-deployment-" +
290                       deployment_uuid)
291     return deployment_dir
292
293
294 def get_criteria_by_test(testname):
295     criteria = ""
296     file = FUNCTEST_REPO + "/ci/testcases.yaml"
297     tiers = tb.TierBuilder("", "", file)
298     for tier in tiers.get_tiers():
299         for test in tier.get_tests():
300             if test.get_name() == testname:
301                 criteria = test.get_criteria()
302
303     return criteria
304
305
306 # ----------------------------------------------------------
307 #
308 #               YAML UTILS
309 #
310 # -----------------------------------------------------------
311 def get_parameter_from_yaml(parameter, file=None):
312     """
313     Returns the value of a given parameter in config_functest.yaml
314     parameter must be given in string format with dots
315     Example: general.openstack.image_name
316     """
317     if file is None:
318         file = os.environ["CONFIG_FUNCTEST_YAML"]
319     with open(file) as f:
320         functest_yaml = yaml.safe_load(f)
321     f.close()
322     value = functest_yaml
323     for element in parameter.split("."):
324         value = value.get(element)
325         if value is None:
326             raise ValueError("The parameter %s is not defined in"
327                              " config_functest.yaml" % parameter)
328     return value