blob: 3e1fb50f95307fd5e098ae583d8eb64d7109050a [file] [log] [blame]
rootd8ab63c2017-07-25 07:19:31 +00001# -*- coding: utf-8 -*-
2'''
3'''
4
5import jinja2
6import logging
7import re
8import requests
9
10import pkg_resources
11
12import salt.pillar
13
14from runtest import tempest_sections
15from runtest.utils import requirements
16
17log = logging.getLogger(__name__)
18
19__virtualname__ = 'runtest'
20
21
22def __virtual__():
23 return __virtualname__
24
25
26CFG_TEMPLATE = """
27{%- for section,options in config.items() -%}
28[{{ section }}]
29{%- for opt,val in options.items() %}
30{{ opt }} = {{ val }}
31{%- endfor %}
32
33{% endfor %}
34"""
35
36REQUIREMENTS_LINK='https://raw.githubusercontent.com/openstack/requirements'
37
38def _get_pillar_for_live_minions(timeout=5, gather_job_timeout=15):
39 client = salt.client.get_local_client(__opts__['conf_file'])
40 pillars = client.cmd('*', 'pillar.items', timeout=timeout,
41 gather_job_timeout=gather_job_timeout)
42
43 return pillars
44
45def generate_tempest_config(dst, *args, **kwargs):
46
47 pillars = _get_pillar_for_live_minions()
48 this_node_pillar = __opts__['pillar']
49 runtest_opts = this_node_pillar.get(__virtualname__, {}).get('tempest', {})
50 config = {}
51
52 for ts in tempest_sections.SECTIONS:
53 ts_inst = ts(pillars, runtest_opts)
54 config[ts_inst.name] = {}
55 opts = {}
56 for opt in ts_inst.options:
57 val = getattr(ts_inst, opt)
58 if val is None:
59 val = runtest_opts.get(ts_inst.name, {}).get(opt, None)
60
61 if val is not None:
62 opts[opt] = val
63
64 config[ts_inst.name] = opts
65
66 data = jinja2.Environment().from_string(CFG_TEMPLATE).render(config=config)
67 with open(dst, 'w') as cfg_file:
68 cfg_file.write(data)
69
70 return config
71
72def check_global_requirements(openstack_version=None, url=None):
73 """Check if our installed requirements are satisfied with upstream.
74 """
Vasyl Saienko570894e2018-01-26 11:07:53 +020075
rootd8ab63c2017-07-25 07:19:31 +000076 if openstack_version is None:
77 openstack_version = __salt__['pillar.get']('runtest:openstack_version')
78 if url is None:
79 url = '%s/%s/global-requirements.txt' % (REQUIREMENTS_LINK, openstack_version)
80
Vasyl Saienko570894e2018-01-26 11:07:53 +020081 resp = requests.get(url)
82 if resp.ok:
83 requirements_content = resp.text
84 else:
85 resp.raise_for_status()
rootd8ab63c2017-07-25 07:19:31 +000086 pkgs = requirements.get_installed_distributions()
87
88 req_deps = {}
89 freq = {}
90 for pkg in pkgs:
91 for line in requirements_content.splitlines():
92 if re.match(r'^%s[ ><!=]' % pkg.project_name, line):
93 req_cond = line.split('#')[0].strip()
94 try:
Vasyl Saienko570894e2018-01-26 11:07:53 +020095 log.info("Checking requirement {req_name}s, requirement"
96 " {req}s".format(req_name=pkg.project_name,
rootd8ab63c2017-07-25 07:19:31 +000097 req=req_cond))
98 pkg_resources.working_set.require(req_cond)
99 except pkg_resources.VersionConflict as ve:
Vasyl Saienko570894e2018-01-26 11:07:53 +0200100 log.warning("Requirement {req_name}s not satisfied. Required "
101 "version {req_cond}s. Installed version "
102 "{inst_version}s. Exception {exc}s".format(
rootd8ab63c2017-07-25 07:19:31 +0000103 req_name=pkg.project_name, req_cond=line,
104 inst_version=pkg.version, exc=ve))
105 freq[pkg.project_name] = {'installed_version': pkg.version,
106 'requirement': line}
107 except Exception as ex: {'error': ex,
108 'requirement': line,
109 'installed_version': pkg.version}
110 return freq
111
112def check_upper_constraints(openstack_version=None, url=None):
113 """Check if our installed requirements are satisfied with upstream upper constraints.
114 """
115 if openstack_version is None:
116 openstack_version = __salt__['pillar.get']('runtest:openstack_version')
Vasyl Saienko570894e2018-01-26 11:07:53 +0200117
rootd8ab63c2017-07-25 07:19:31 +0000118 if url is None:
119 url = '%s/%s/upper-constraints.txt' % (REQUIREMENTS_LINK, openstack_version)
120
Vasyl Saienko570894e2018-01-26 11:07:53 +0200121 resp = requests.get(url)
122 if resp.ok:
123 constraints_content = resp.text
124 else:
125 resp.raise_for_status()
rootd8ab63c2017-07-25 07:19:31 +0000126 pkgs = requirements.get_installed_distributions()
127
128 req_deps = {}
129 freq = {}
130 for pkg in pkgs:
131 for line in constraints_content.splitlines():
Vasyl Saienko570894e2018-01-26 11:07:53 +0200132 if re.match(r'^%s[ ><!=]' % pkg.project_name, line, re.IGNORECASE):
rootd8ab63c2017-07-25 07:19:31 +0000133 req_cond = line.split('#')[0].strip()
134 try:
Vasyl Saienko570894e2018-01-26 11:07:53 +0200135 log.info("Checking requirement {req_name}s, requirement"
136 " {req}s".format(req_name=pkg.project_name,
rootd8ab63c2017-07-25 07:19:31 +0000137 req=req_cond))
138 pkg_resources.working_set.require(req_cond)
139 except pkg_resources.VersionConflict as ve:
Vasyl Saienko570894e2018-01-26 11:07:53 +0200140 log.warning("Requirement {req_name}s not satisfied. Required "
141 "version {req_cond}s. Installed version "
142 "{inst_version}s. Exception {exc}s".format(
rootd8ab63c2017-07-25 07:19:31 +0000143 req_name=pkg.project_name, req_cond=line,
144 inst_version=pkg.version, exc=ve))
145 freq[pkg.project_name] = {'installed_version': pkg.version,
146 'requirement': line,
Vasyl Saienko570894e2018-01-26 11:07:53 +0200147 'error': str(ve)}
148 except Exception as ex:
149 freq[pkg.project_name] = {'error': str(ex),
150 'requirement': line,
151 'installed_version': pkg.version}
rootd8ab63c2017-07-25 07:19:31 +0000152 return freq