Alex | 0989ecf | 2022-03-29 13:43:21 -0500 | [diff] [blame^] | 1 | # Author: Alex Savatieiev (osavatieiev@mirantis.com; a.savex@gmail.com) |
| 2 | # Copyright 2019-2022 Mirantis, Inc. |
savex | 4448e13 | 2018-04-25 15:51:14 +0200 | [diff] [blame] | 3 | import json |
savex | 4448e13 | 2018-04-25 15:51:14 +0200 | [diff] [blame] | 4 | |
Alex | 3ebc563 | 2019-04-18 16:47:18 -0500 | [diff] [blame] | 5 | from cfg_checker.common import const, logger_cli |
Alex | 4148552 | 2019-04-12 17:26:18 -0500 | [diff] [blame] | 6 | from cfg_checker.common.exception import ConfigException |
Alex | 26b8a8c | 2019-10-09 17:09:07 -0500 | [diff] [blame] | 7 | from cfg_checker.common.other import merge_dict |
Alex | 9a4ad21 | 2020-10-01 18:04:25 -0500 | [diff] [blame] | 8 | from cfg_checker.common.settings import ENV_TYPE_SALT |
Alex | 4148552 | 2019-04-12 17:26:18 -0500 | [diff] [blame] | 9 | from cfg_checker.helpers.console_utils import Progress |
Alex | d0391d4 | 2019-05-21 18:48:55 -0500 | [diff] [blame] | 10 | from cfg_checker.modules.packages.repos import RepoManager |
Alex | 9a4ad21 | 2020-10-01 18:04:25 -0500 | [diff] [blame] | 11 | from cfg_checker.nodes import SaltNodes, KubeNodes |
Alex | 4148552 | 2019-04-12 17:26:18 -0500 | [diff] [blame] | 12 | from cfg_checker.reports import reporter |
| 13 | |
Alex | 3bc95f6 | 2020-03-05 17:00:04 -0600 | [diff] [blame] | 14 | from .versions import DebianVersion, PkgVersions, VersionCmpResult |
savex | 4448e13 | 2018-04-25 15:51:14 +0200 | [diff] [blame] | 15 | |
| 16 | |
Alex | e0c5b9e | 2019-04-23 18:51:23 -0500 | [diff] [blame] | 17 | class CloudPackageChecker(object): |
Alex | e9908f7 | 2020-05-19 16:04:53 -0500 | [diff] [blame] | 18 | def __init__( |
| 19 | self, |
Alex | 9a4ad21 | 2020-10-01 18:04:25 -0500 | [diff] [blame] | 20 | config, |
Alex | e9908f7 | 2020-05-19 16:04:53 -0500 | [diff] [blame] | 21 | force_tag=None, |
| 22 | exclude_keywords=[], |
| 23 | skip_list=None, |
| 24 | skip_list_file=None |
| 25 | ): |
Alex | 9a4ad21 | 2020-10-01 18:04:25 -0500 | [diff] [blame] | 26 | # check that this env tag is present in Manager |
| 27 | self.env_config = config |
| 28 | self.rm = RepoManager() |
| 29 | self.force_tag = force_tag |
| 30 | self.exclude_keywords = exclude_keywords |
| 31 | |
Alex | d0391d4 | 2019-05-21 18:48:55 -0500 | [diff] [blame] | 32 | # Init salt master info |
Alex | 9a4ad21 | 2020-10-01 18:04:25 -0500 | [diff] [blame] | 33 | if not self.master.nodes: |
| 34 | self.master.nodes = self.master.get_nodes( |
Alex | e9908f7 | 2020-05-19 16:04:53 -0500 | [diff] [blame] | 35 | skip_list=skip_list, |
| 36 | skip_list_file=skip_list_file |
| 37 | ) |
Alex | d0391d4 | 2019-05-21 18:48:55 -0500 | [diff] [blame] | 38 | |
Alex | 9a4ad21 | 2020-10-01 18:04:25 -0500 | [diff] [blame] | 39 | _tags = self.rm.get_available_tags(tag=self.master.mcp_release) |
Alex | d0391d4 | 2019-05-21 18:48:55 -0500 | [diff] [blame] | 40 | if not _tags: |
| 41 | logger_cli.warning( |
Alex | 9a4ad21 | 2020-10-01 18:04:25 -0500 | [diff] [blame] | 42 | "\n# WARNING: '{0}' is not listed in repo index. " |
Alex | d0391d4 | 2019-05-21 18:48:55 -0500 | [diff] [blame] | 43 | "Consider running:\n\t{1}\nto add info on this tag's " |
| 44 | "release package versions".format( |
Alex | 9a4ad21 | 2020-10-01 18:04:25 -0500 | [diff] [blame] | 45 | self.master.mcp_release, |
| 46 | "mcp-checker packages versions --tag <target_tag>" |
Alex | d0391d4 | 2019-05-21 18:48:55 -0500 | [diff] [blame] | 47 | ) |
| 48 | ) |
| 49 | |
Alex | 4148552 | 2019-04-12 17:26:18 -0500 | [diff] [blame] | 50 | @staticmethod |
| 51 | def presort_packages(all_packages, full=None): |
| 52 | logger_cli.info("-> Presorting packages") |
| 53 | # labels |
| 54 | _data = {} |
| 55 | _data = { |
| 56 | "cs": { |
| 57 | "ok": const.VERSION_OK, |
| 58 | "up": const.VERSION_UP, |
| 59 | "down": const.VERSION_DOWN, |
Alex | 26b8a8c | 2019-10-09 17:09:07 -0500 | [diff] [blame] | 60 | "warn": const.VERSION_WARN, |
Alex | 4148552 | 2019-04-12 17:26:18 -0500 | [diff] [blame] | 61 | "err": const.VERSION_ERR |
| 62 | }, |
| 63 | "ca": { |
| 64 | "na": const.ACT_NA, |
| 65 | "up": const.ACT_UPGRADE, |
| 66 | "need_up": const.ACT_NEED_UP, |
| 67 | "need_down": const.ACT_NEED_DOWN, |
| 68 | "repo": const.ACT_REPO |
| 69 | } |
| 70 | } |
| 71 | _data['status_err'] = const.VERSION_ERR |
Alex | 26b8a8c | 2019-10-09 17:09:07 -0500 | [diff] [blame] | 72 | _data['status_warn'] = const.VERSION_WARN |
Alex | 4148552 | 2019-04-12 17:26:18 -0500 | [diff] [blame] | 73 | _data['status_down'] = const.VERSION_DOWN |
Alex | e9908f7 | 2020-05-19 16:04:53 -0500 | [diff] [blame] | 74 | _data['status_skip'] = const.VERSION_NA |
Alex | 4148552 | 2019-04-12 17:26:18 -0500 | [diff] [blame] | 75 | |
| 76 | # Presort packages |
| 77 | _data['critical'] = {} |
| 78 | _data['system'] = {} |
| 79 | _data['other'] = {} |
| 80 | _data['unlisted'] = {} |
| 81 | |
| 82 | _l = len(all_packages) |
| 83 | _progress = Progress(_l) |
| 84 | _progress_index = 0 |
| 85 | # counters |
| 86 | _ec = _es = _eo = _eu = 0 |
Alex | 26b8a8c | 2019-10-09 17:09:07 -0500 | [diff] [blame] | 87 | _wc = _ws = _wo = _wu = 0 |
Alex | 4148552 | 2019-04-12 17:26:18 -0500 | [diff] [blame] | 88 | _dc = _ds = _do = _du = 0 |
| 89 | while _progress_index < _l: |
| 90 | # progress bar |
| 91 | _progress_index += 1 |
| 92 | _progress.write_progress(_progress_index) |
| 93 | # sort packages |
| 94 | _pn, _val = all_packages.popitem() |
Alex | d0391d4 | 2019-05-21 18:48:55 -0500 | [diff] [blame] | 95 | _c = _val['desc']['section'] |
Alex | 3bc95f6 | 2020-03-05 17:00:04 -0600 | [diff] [blame] | 96 | _rkeys = _val['results'].keys() |
Alex | d0391d4 | 2019-05-21 18:48:55 -0500 | [diff] [blame] | 97 | |
Alex | e0c5b9e | 2019-04-23 18:51:23 -0500 | [diff] [blame] | 98 | if not full: |
Alex | 4148552 | 2019-04-12 17:26:18 -0500 | [diff] [blame] | 99 | # Check if this packet has errors |
| 100 | # if all is ok -> just skip it |
| 101 | _max_status = max(_val['results'].keys()) |
| 102 | if _max_status <= const.VERSION_OK: |
| 103 | _max_action = max(_val['results'][_max_status].keys()) |
| 104 | if _max_action == const.ACT_NA: |
Alex | d0391d4 | 2019-05-21 18:48:55 -0500 | [diff] [blame] | 105 | # this package does not have any comments |
Alex | 4148552 | 2019-04-12 17:26:18 -0500 | [diff] [blame] | 106 | # ...just skip it from report |
| 107 | continue |
| 108 | |
Alex | 26b8a8c | 2019-10-09 17:09:07 -0500 | [diff] [blame] | 109 | _differ = len(set(_val['results'].keys())) > 1 |
| 110 | if _differ: |
| 111 | # in case package has different status across nodes |
| 112 | # Warning becomes Error. |
| 113 | if const.VERSION_WARN in _val['results']: |
| 114 | if const.VERSION_ERR in _val['results']: |
| 115 | # add warns to err |
| 116 | # should never happen, though |
| 117 | merge_dict( |
| 118 | _val['results'].pop(const.VERSION_WARN), |
| 119 | _val['results'][const.VERSION_ERR] |
| 120 | ) |
| 121 | else: |
| 122 | _val['results'][const.VERSION_ERR] = \ |
| 123 | _val['results'].pop(const.VERSION_WARN) |
| 124 | else: |
| 125 | # in case package has same status on all nodes |
| 126 | # Error becomes Warning |
| 127 | if const.VERSION_ERR in _val['results']: |
| 128 | if const.VERSION_WARN in _val['results']: |
| 129 | # add warns to err |
| 130 | # should never happen, though |
| 131 | merge_dict( |
| 132 | _val['results'].pop(const.VERSION_ERR), |
| 133 | _val['results'][const.VERSION_WARN] |
| 134 | ) |
| 135 | else: |
| 136 | _val['results'][const.VERSION_WARN] = \ |
| 137 | _val['results'].pop(const.VERSION_ERR) |
| 138 | |
Alex | d0391d4 | 2019-05-21 18:48:55 -0500 | [diff] [blame] | 139 | if len(_c) > 0 and _val['is_mirantis'] is None: |
Alex | 4148552 | 2019-04-12 17:26:18 -0500 | [diff] [blame] | 140 | # not listed package in version lib |
| 141 | _data['unlisted'].update({ |
| 142 | _pn: _val |
| 143 | }) |
Alex | 3bc95f6 | 2020-03-05 17:00:04 -0600 | [diff] [blame] | 144 | _eu += sum(x == const.VERSION_ERR for x in _rkeys) |
| 145 | _wu += sum(x == const.VERSION_WARN for x in _rkeys) |
| 146 | _du += sum(x == const.VERSION_DOWN for x in _rkeys) |
Alex | 4148552 | 2019-04-12 17:26:18 -0500 | [diff] [blame] | 147 | # mirantis/critical |
Alex | d0391d4 | 2019-05-21 18:48:55 -0500 | [diff] [blame] | 148 | # elif len(_c) > 0 and _c != 'System': |
| 149 | elif _val['is_mirantis']: |
Alex | 4148552 | 2019-04-12 17:26:18 -0500 | [diff] [blame] | 150 | # not blank and not system |
| 151 | _data['critical'].update({ |
| 152 | _pn: _val |
| 153 | }) |
Alex | 3bc95f6 | 2020-03-05 17:00:04 -0600 | [diff] [blame] | 154 | _ec += sum(x == const.VERSION_ERR for x in _rkeys) |
| 155 | _wc += sum(x == const.VERSION_WARN for x in _rkeys) |
| 156 | _dc += sum(x == const.VERSION_DOWN for x in _rkeys) |
Alex | 4148552 | 2019-04-12 17:26:18 -0500 | [diff] [blame] | 157 | # system |
| 158 | elif _c == 'System': |
| 159 | _data['system'].update({ |
| 160 | _pn: _val |
| 161 | }) |
Alex | 3bc95f6 | 2020-03-05 17:00:04 -0600 | [diff] [blame] | 162 | _es += sum(x == const.VERSION_ERR for x in _rkeys) |
| 163 | _ws += sum(x == const.VERSION_WARN for x in _rkeys) |
| 164 | _ds += sum(x == const.VERSION_DOWN for x in _rkeys) |
Alex | 4148552 | 2019-04-12 17:26:18 -0500 | [diff] [blame] | 165 | # rest |
| 166 | else: |
| 167 | _data['other'].update({ |
| 168 | _pn: _val |
| 169 | }) |
Alex | 3bc95f6 | 2020-03-05 17:00:04 -0600 | [diff] [blame] | 170 | _eo += sum(x == const.VERSION_ERR for x in _rkeys) |
| 171 | _wo += sum(x == const.VERSION_WARN for x in _rkeys) |
| 172 | _do += sum(x == const.VERSION_DOWN for x in _rkeys) |
Alex | 4148552 | 2019-04-12 17:26:18 -0500 | [diff] [blame] | 173 | |
Alex | d9fd85e | 2019-05-16 16:58:24 -0500 | [diff] [blame] | 174 | _progress.end() |
Alex | 4148552 | 2019-04-12 17:26:18 -0500 | [diff] [blame] | 175 | |
| 176 | _data['errors'] = { |
| 177 | 'mirantis': _ec, |
| 178 | 'system': _es, |
| 179 | 'other': _eo, |
| 180 | 'unlisted': _eu |
| 181 | } |
Alex | 26b8a8c | 2019-10-09 17:09:07 -0500 | [diff] [blame] | 182 | _data['warnings'] = { |
| 183 | 'mirantis': _wc, |
| 184 | 'system': _ws, |
| 185 | 'other': _wo, |
| 186 | 'unlisted': _wu |
| 187 | } |
Alex | 4148552 | 2019-04-12 17:26:18 -0500 | [diff] [blame] | 188 | _data['downgrades'] = { |
| 189 | 'mirantis': _dc, |
| 190 | 'system': _ds, |
| 191 | 'other': _do, |
| 192 | 'unlisted': _du |
| 193 | } |
| 194 | |
| 195 | return _data |
| 196 | |
savex | 4448e13 | 2018-04-25 15:51:14 +0200 | [diff] [blame] | 197 | def collect_packages(self): |
| 198 | """ |
| 199 | Check package versions in repos vs installed |
| 200 | |
| 201 | :return: no return values, all date put to dict in place |
| 202 | """ |
Alex | 4148552 | 2019-04-12 17:26:18 -0500 | [diff] [blame] | 203 | # Preload OpenStack release versions |
Alex | 9a4ad21 | 2020-10-01 18:04:25 -0500 | [diff] [blame] | 204 | _desc = PkgVersions(self.env_config) |
Alex | 3ebc563 | 2019-04-18 16:47:18 -0500 | [diff] [blame] | 205 | logger_cli.info( |
| 206 | "# Cross-comparing: Installed vs Candidates vs Release" |
| 207 | ) |
Alex | d0391d4 | 2019-05-21 18:48:55 -0500 | [diff] [blame] | 208 | # shortcuts for this cloud values |
Alex | 9a4ad21 | 2020-10-01 18:04:25 -0500 | [diff] [blame] | 209 | _os = self.master.openstack_release |
| 210 | _mcp = self.master.mcp_release |
Alex | e9547d8 | 2019-06-03 15:22:50 -0500 | [diff] [blame] | 211 | _t = [self.force_tag] if self.force_tag else [] |
| 212 | _t.append(_mcp) |
| 213 | |
| 214 | logger_cli.info("# Tag search list: {}".format(", ".join(_t))) |
| 215 | logger_cli.info("# Openstack version: {}".format(_os)) |
| 216 | logger_cli.info( |
| 217 | "# Release versions repos keyword exclude list: {}".format( |
Alex | 9e4bfaf | 2019-06-11 15:21:59 -0500 | [diff] [blame] | 218 | ", ".join(self.exclude_keywords) |
Alex | e9547d8 | 2019-06-03 15:22:50 -0500 | [diff] [blame] | 219 | ) |
| 220 | ) |
| 221 | |
Alex | d0391d4 | 2019-05-21 18:48:55 -0500 | [diff] [blame] | 222 | # Progress class |
Alex | 9a4ad21 | 2020-10-01 18:04:25 -0500 | [diff] [blame] | 223 | _progress = Progress(len(self.master.nodes.keys())) |
Alex | 4148552 | 2019-04-12 17:26:18 -0500 | [diff] [blame] | 224 | _progress_index = 0 |
| 225 | _total_processed = 0 |
Alex Savatieiev | 3db12a7 | 2019-03-22 16:32:31 -0500 | [diff] [blame] | 226 | # Collect packages from all of the nodes in flat dict |
Alex | 4148552 | 2019-04-12 17:26:18 -0500 | [diff] [blame] | 227 | _all_packages = {} |
Alex | 9a4ad21 | 2020-10-01 18:04:25 -0500 | [diff] [blame] | 228 | for node_name, node_value in self.master.nodes.items(): |
Alex | 4148552 | 2019-04-12 17:26:18 -0500 | [diff] [blame] | 229 | _uniq_len = len(_all_packages.keys()) |
| 230 | _progress_index += 1 |
Alex | d0391d4 | 2019-05-21 18:48:55 -0500 | [diff] [blame] | 231 | # progress updates shown before next node only |
| 232 | # it is costly operation to do it for each of the 150k packages |
Alex | 4148552 | 2019-04-12 17:26:18 -0500 | [diff] [blame] | 233 | _progress.write_progress( |
| 234 | _progress_index, |
| 235 | note="/ {} uniq out of {} packages found".format( |
| 236 | _uniq_len, |
| 237 | _total_processed |
| 238 | ) |
| 239 | ) |
Alex | 3bc95f6 | 2020-03-05 17:00:04 -0600 | [diff] [blame] | 240 | for _name, _value in node_value['packages'].items(): |
Alex | 4148552 | 2019-04-12 17:26:18 -0500 | [diff] [blame] | 241 | _total_processed += 1 |
Alex | cf91b18 | 2019-05-31 11:57:07 -0500 | [diff] [blame] | 242 | # Parse versions from nodes |
Alex | 4148552 | 2019-04-12 17:26:18 -0500 | [diff] [blame] | 243 | _ver_ins = DebianVersion(_value['installed']) |
| 244 | _ver_can = DebianVersion(_value['candidate']) |
| 245 | |
Alex | cf91b18 | 2019-05-31 11:57:07 -0500 | [diff] [blame] | 246 | # Process package description and release version |
| 247 | # at a first sight |
Alex | 4148552 | 2019-04-12 17:26:18 -0500 | [diff] [blame] | 248 | if _name not in _all_packages: |
Alex | cf91b18 | 2019-05-31 11:57:07 -0500 | [diff] [blame] | 249 | # get node attributes |
Alex | 9a4ad21 | 2020-10-01 18:04:25 -0500 | [diff] [blame] | 250 | _linux = \ |
| 251 | self.master.nodes[node_name]['linux_codename'] |
| 252 | _arch = self.master.nodes[node_name]['linux_arch'] |
Alex | e9547d8 | 2019-06-03 15:22:50 -0500 | [diff] [blame] | 253 | # get versions for tag, Openstack release and repo headers |
| 254 | # excluding 'nightly' repos by default |
| 255 | _r = {} |
| 256 | # if there is a forced tag = use it |
| 257 | if self.force_tag: |
| 258 | _r = self.rm.get_filtered_versions( |
| 259 | _name, |
| 260 | tag=self.force_tag, |
| 261 | include=[_os, _linux, _arch], |
Alex | 9e4bfaf | 2019-06-11 15:21:59 -0500 | [diff] [blame] | 262 | exclude=self.exclude_keywords |
Alex | e9547d8 | 2019-06-03 15:22:50 -0500 | [diff] [blame] | 263 | ) |
| 264 | # if nothing found, look everywhere |
Alex | 9e4bfaf | 2019-06-11 15:21:59 -0500 | [diff] [blame] | 265 | # but with no word 'openstack' |
Alex | e9547d8 | 2019-06-03 15:22:50 -0500 | [diff] [blame] | 266 | if not _r: |
| 267 | _r = self.rm.get_filtered_versions( |
| 268 | _name, |
| 269 | tag=self.force_tag, |
| 270 | include=[_linux, _arch], |
Alex | 9e4bfaf | 2019-06-11 15:21:59 -0500 | [diff] [blame] | 271 | exclude=self.exclude_keywords + ['openstack'] |
Alex | e9547d8 | 2019-06-03 15:22:50 -0500 | [diff] [blame] | 272 | ) |
| 273 | # if nothing is found at this point, |
| 274 | # repeat search using normal tags |
| 275 | if not _r: |
| 276 | _r = self.rm.get_filtered_versions( |
| 277 | _name, |
| 278 | tag=_mcp, |
| 279 | include=[_os, _linux, _arch], |
Alex | 9e4bfaf | 2019-06-11 15:21:59 -0500 | [diff] [blame] | 280 | exclude=self.exclude_keywords |
Alex | e9547d8 | 2019-06-03 15:22:50 -0500 | [diff] [blame] | 281 | ) |
| 282 | # Once again, if nothing found, look everywhere |
| 283 | if not _r: |
| 284 | _r = self.rm.get_filtered_versions( |
| 285 | _name, |
| 286 | tag=_mcp, |
| 287 | include=[_linux, _arch], |
Alex | 9e4bfaf | 2019-06-11 15:21:59 -0500 | [diff] [blame] | 288 | exclude=self.exclude_keywords + ['openstack'] |
Alex | e9547d8 | 2019-06-03 15:22:50 -0500 | [diff] [blame] | 289 | ) |
Alex | cf91b18 | 2019-05-31 11:57:07 -0500 | [diff] [blame] | 290 | # repack versions in flat format |
Alex | d0391d4 | 2019-05-21 18:48:55 -0500 | [diff] [blame] | 291 | _vs = {} |
| 292 | _sections = {} |
| 293 | _apps = {} |
Alex | 3bc95f6 | 2020-03-05 17:00:04 -0600 | [diff] [blame] | 294 | for s, apps in _r.items(): |
| 295 | for a, versions in apps.items(): |
| 296 | for v, repos in versions.items(): |
Alex | d0391d4 | 2019-05-21 18:48:55 -0500 | [diff] [blame] | 297 | for repo in repos: |
Alex | cf91b18 | 2019-05-31 11:57:07 -0500 | [diff] [blame] | 298 | if v not in _vs: |
| 299 | _vs[v] = [] |
| 300 | _vs[v].append(repo) |
| 301 | if v not in _sections: |
| 302 | _sections[v] = [] |
| 303 | _sections[v].append(s) |
| 304 | if v not in _apps: |
| 305 | _apps[v] = [] |
| 306 | _apps[v].append(a) |
| 307 | # search for the newest version among filtered |
Alex | d0391d4 | 2019-05-21 18:48:55 -0500 | [diff] [blame] | 308 | _r_desc = [] |
Alex | 3bc95f6 | 2020-03-05 17:00:04 -0600 | [diff] [blame] | 309 | _vs_keys = iter(_vs.keys()) |
| 310 | # get next version, if any |
| 311 | try: |
| 312 | _newest = DebianVersion(next(_vs_keys)) |
| 313 | except StopIteration: |
Alex | d0391d4 | 2019-05-21 18:48:55 -0500 | [diff] [blame] | 314 | _newest = DebianVersion('') |
Alex | 3bc95f6 | 2020-03-05 17:00:04 -0600 | [diff] [blame] | 315 | # iterate others, if any |
Alex | d0391d4 | 2019-05-21 18:48:55 -0500 | [diff] [blame] | 316 | for v in _vs_keys: |
| 317 | _this = DebianVersion(v) |
| 318 | if _this > _newest: |
| 319 | _newest = _this |
Alex | d0391d4 | 2019-05-21 18:48:55 -0500 | [diff] [blame] | 320 | _release = _newest |
Alex | cf91b18 | 2019-05-31 11:57:07 -0500 | [diff] [blame] | 321 | # Get best description for the package |
Alex | d0391d4 | 2019-05-21 18:48:55 -0500 | [diff] [blame] | 322 | if _release.version != 'n/a': |
| 323 | _r_desc = _vs[_release.version] |
| 324 | # preload special description |
Alex | 4148552 | 2019-04-12 17:26:18 -0500 | [diff] [blame] | 325 | if _desc[_name]: |
Alex | 4148552 | 2019-04-12 17:26:18 -0500 | [diff] [blame] | 326 | _pkg_desc = _desc[_name] |
| 327 | else: |
Alex | 4148552 | 2019-04-12 17:26:18 -0500 | [diff] [blame] | 328 | _pkg_desc = _desc.dummy_desc |
Alex | cf91b18 | 2019-05-31 11:57:07 -0500 | [diff] [blame] | 329 | # Save repos list and desc for this version |
Alex | d0391d4 | 2019-05-21 18:48:55 -0500 | [diff] [blame] | 330 | # Check if we can provide better from the package |
| 331 | if _release.version != 'n/a': |
| 332 | if not _pkg_desc['section']: |
| 333 | _pkg_desc['section'] = \ |
| 334 | "/".join(_sections[_release.version]) |
| 335 | if not _pkg_desc['app']: |
| 336 | _pkg_desc['app'] = \ |
| 337 | "/".join(_apps[_release.version]) |
Alex | 3ebc563 | 2019-04-18 16:47:18 -0500 | [diff] [blame] | 338 | |
Alex | cf91b18 | 2019-05-31 11:57:07 -0500 | [diff] [blame] | 339 | # Populate package info, once for package |
Alex | d0391d4 | 2019-05-21 18:48:55 -0500 | [diff] [blame] | 340 | _m = _r_desc[0]["maintainer"] if _r_desc else 'n/a' |
Alex | 4148552 | 2019-04-12 17:26:18 -0500 | [diff] [blame] | 341 | _all_packages[_name] = { |
| 342 | "desc": _pkg_desc, |
Alex | d0391d4 | 2019-05-21 18:48:55 -0500 | [diff] [blame] | 343 | "repos": _r_desc, |
| 344 | "maintainer": _m, |
| 345 | "is_mirantis": self.rm.is_mirantis( |
| 346 | _name, |
Alex | cf91b18 | 2019-05-31 11:57:07 -0500 | [diff] [blame] | 347 | tag=_mcp |
Alex | d0391d4 | 2019-05-21 18:48:55 -0500 | [diff] [blame] | 348 | ), |
Alex | 4148552 | 2019-04-12 17:26:18 -0500 | [diff] [blame] | 349 | "results": {}, |
| 350 | "r": _release, |
Alex Savatieiev | 3db12a7 | 2019-03-22 16:32:31 -0500 | [diff] [blame] | 351 | } |
Alex | cf91b18 | 2019-05-31 11:57:07 -0500 | [diff] [blame] | 352 | # Cross-compare versions |
Alex | 4148552 | 2019-04-12 17:26:18 -0500 | [diff] [blame] | 353 | _cmp = VersionCmpResult( |
| 354 | _ver_ins, |
| 355 | _ver_can, |
| 356 | _all_packages[_name]['r'] |
| 357 | ) |
Alex | cf91b18 | 2019-05-31 11:57:07 -0500 | [diff] [blame] | 358 | # Update results structure |
Alex | 4148552 | 2019-04-12 17:26:18 -0500 | [diff] [blame] | 359 | # shortcut to results |
| 360 | _res = _all_packages[_name]['results'] |
| 361 | # update status |
| 362 | if _cmp.status not in _res: |
| 363 | _res[_cmp.status] = {} |
| 364 | # update action |
| 365 | if _cmp.action not in _res[_cmp.status]: |
| 366 | _res[_cmp.status][_cmp.action] = {} |
| 367 | # update node |
| 368 | if node_name not in _res[_cmp.status][_cmp.action]: |
| 369 | _res[_cmp.status][_cmp.action][node_name] = {} |
| 370 | # put result |
| 371 | _res[_cmp.status][_cmp.action][node_name] = { |
| 372 | 'i': _ver_ins, |
| 373 | 'c': _ver_can, |
| 374 | 'res': _cmp, |
| 375 | 'raw': _value['raw'] |
| 376 | } |
savex | 4448e13 | 2018-04-25 15:51:14 +0200 | [diff] [blame] | 377 | |
Alex | 4148552 | 2019-04-12 17:26:18 -0500 | [diff] [blame] | 378 | self._packages = _all_packages |
Alex | d9fd85e | 2019-05-16 16:58:24 -0500 | [diff] [blame] | 379 | _progress.end() |
savex | 4448e13 | 2018-04-25 15:51:14 +0200 | [diff] [blame] | 380 | |
Alex | 4148552 | 2019-04-12 17:26:18 -0500 | [diff] [blame] | 381 | def create_report(self, filename, rtype, full=None): |
savex | 4448e13 | 2018-04-25 15:51:14 +0200 | [diff] [blame] | 382 | """ |
| 383 | Create static html showing packages diff per node |
| 384 | |
| 385 | :return: buff with html |
| 386 | """ |
Alex Savatieiev | 42b89fa | 2019-03-07 18:45:26 -0600 | [diff] [blame] | 387 | logger_cli.info("# Generating report to '{}'".format(filename)) |
Alex | 4148552 | 2019-04-12 17:26:18 -0500 | [diff] [blame] | 388 | if rtype == 'html': |
Alex | 9a4ad21 | 2020-10-01 18:04:25 -0500 | [diff] [blame] | 389 | _type = reporter.HTMLPackageCandidates(self.master) |
Alex | 4148552 | 2019-04-12 17:26:18 -0500 | [diff] [blame] | 390 | elif rtype == 'csv': |
Alex | 9a4ad21 | 2020-10-01 18:04:25 -0500 | [diff] [blame] | 391 | _type = reporter.CSVAllPackages(self.master) |
Alex | 4148552 | 2019-04-12 17:26:18 -0500 | [diff] [blame] | 392 | else: |
| 393 | raise ConfigException("Report type not set") |
Alex Savatieiev | d48994d | 2018-12-13 12:13:00 +0100 | [diff] [blame] | 394 | _report = reporter.ReportToFile( |
Alex | 4148552 | 2019-04-12 17:26:18 -0500 | [diff] [blame] | 395 | _type, |
savex | 4448e13 | 2018-04-25 15:51:14 +0200 | [diff] [blame] | 396 | filename |
| 397 | ) |
Alex | 4148552 | 2019-04-12 17:26:18 -0500 | [diff] [blame] | 398 | payload = { |
Alex | 9a4ad21 | 2020-10-01 18:04:25 -0500 | [diff] [blame] | 399 | "nodes": self.master.nodes, |
| 400 | "mcp_release": self.master.mcp_release, |
| 401 | "openstack_release": self.master.openstack_release |
Alex | 4148552 | 2019-04-12 17:26:18 -0500 | [diff] [blame] | 402 | } |
| 403 | payload.update(self.presort_packages(self._packages, full)) |
| 404 | _report(payload) |
Alex Savatieiev | 799bee3 | 2019-02-20 17:19:26 -0600 | [diff] [blame] | 405 | logger_cli.info("-> Done") |
Alex | 9a4ad21 | 2020-10-01 18:04:25 -0500 | [diff] [blame] | 406 | |
| 407 | def collect_installed_packages(self): |
| 408 | """ |
| 409 | Collect installed packages on each node |
| 410 | sets 'installed' dict property in the class |
| 411 | |
| 412 | :return: none |
| 413 | """ |
| 414 | logger_cli.info("# Collecting installed packages") |
| 415 | if self.master.env_type == ENV_TYPE_SALT: |
| 416 | self.master.prepare_script_on_active_nodes("pkg_versions.py") |
| 417 | _result = self.master.execute_script_on_active_nodes( |
| 418 | "pkg_versions.py" |
| 419 | ) |
| 420 | |
| 421 | for key in self.master.nodes.keys(): |
| 422 | # due to much data to be passed from salt, it is happening in order |
| 423 | if key in _result and _result[key]: |
| 424 | _text = _result[key] |
| 425 | try: |
| 426 | _dict = json.loads(_text[_text.find('{'):]) |
| 427 | except ValueError: |
| 428 | logger_cli.info("... no JSON for '{}'".format( |
| 429 | key |
| 430 | )) |
| 431 | logger_cli.debug( |
| 432 | "ERROR:\n{}\n".format(_text[:_text.find('{')]) |
| 433 | ) |
| 434 | _dict = {} |
| 435 | |
| 436 | self.master.nodes[key]['packages'] = _dict |
| 437 | else: |
| 438 | self.master.nodes[key]['packages'] = {} |
| 439 | logger_cli.debug("... {} has {} packages installed".format( |
| 440 | key, |
| 441 | len(self.master.nodes[key]['packages'].keys()) |
| 442 | )) |
| 443 | logger_cli.info("-> Done") |
| 444 | |
| 445 | |
| 446 | class SaltCloudPackageChecker(CloudPackageChecker): |
| 447 | def __init__( |
| 448 | self, |
| 449 | config, |
| 450 | force_tag=None, |
| 451 | exclude_keywords=[], |
| 452 | skip_list=None, |
| 453 | skip_list_file=None |
| 454 | ): |
| 455 | self.master = SaltNodes(config) |
| 456 | super(SaltCloudPackageChecker, self).__init__( |
| 457 | config, |
Alex | ccb72e0 | 2021-01-20 16:38:03 -0600 | [diff] [blame] | 458 | force_tag=force_tag, |
Alex | 9a4ad21 | 2020-10-01 18:04:25 -0500 | [diff] [blame] | 459 | exclude_keywords=[], |
Alex | 359e575 | 2021-08-16 17:28:30 -0500 | [diff] [blame] | 460 | skip_list=skip_list, |
| 461 | skip_list_file=skip_list_file |
Alex | 9a4ad21 | 2020-10-01 18:04:25 -0500 | [diff] [blame] | 462 | ) |
| 463 | |
| 464 | |
| 465 | class KubeCloudPackageChecker(CloudPackageChecker): |
| 466 | def __init__( |
| 467 | self, |
| 468 | config, |
| 469 | force_tag=None, |
| 470 | exclude_keywords=[], |
| 471 | skip_list=None, |
| 472 | skip_list_file=None |
| 473 | ): |
| 474 | self.master = KubeNodes(config) |
| 475 | super(KubeCloudPackageChecker, self).__init__( |
| 476 | config, |
Alex | ccb72e0 | 2021-01-20 16:38:03 -0600 | [diff] [blame] | 477 | force_tag=force_tag, |
Alex | 9a4ad21 | 2020-10-01 18:04:25 -0500 | [diff] [blame] | 478 | exclude_keywords=[], |
Alex | 359e575 | 2021-08-16 17:28:30 -0500 | [diff] [blame] | 479 | skip_list=skip_list, |
| 480 | skip_list_file=skip_list_file |
Alex | 9a4ad21 | 2020-10-01 18:04:25 -0500 | [diff] [blame] | 481 | ) |