Merge upstream version
Related-PROD: PROD-28199
Change-Id: I5d9dbde1c3ac577fb30fa5d6b1ff18bcee28a0d7
diff --git a/README.md b/README.md
index 044422c..cb2d832 100644
--- a/README.md
+++ b/README.md
@@ -4,12 +4,20 @@
# Local run
It is pretty simple:
-- deploy on cfg node
-- check your local.env file for parameters
-- ...run: `cfg_check -h`
+- deploy on cfg node, using root creds, on /root/
+```bash
+git clone https://github.com/savex/salt-cfg-checker
+cd salt-cfg-checker
+virtualenv .cfgcheck
+source .cfgcheck/bin/activate
+pip install -r requirements.txt
+```
+- you can check your local.env file for parameters (no need to update for running on cfg node)
+- packages report (HTML): `mcp_check packages report --html cloud-packages.html`
+- packages report (CSV): `mcp_check packages report --csv cloud-packages.csv`
# External cloud
-Be sure to
+You can also create your env file to connect to env
- create your *.env file
or supply environment vars to module other way
- in the `env` file set host and user for SSH.
@@ -17,11 +25,16 @@
- if node listing fails, execute `salt-key` on master
and create an `etc/nodes.list` file with minions list
+# Version history
+- [*Done*] Update messages to same style
+- [*Done*] Release versions support with customizable updates
+- [*Done*] Upgrades, errors and downgrades detection
+- [*Done*] Proper Debian package [version](https://www.debian.org/doc/debian-policy/ch-controlfields.html#version) naming convention support
+
TODO:
- Check root on startup, exit
- Prepare script to create venv
- Format reclass compare file
-- Update messages to same style
+
Cheers!
-
diff --git a/cfg_checker/cfg_check.py b/cfg_checker/cfg_check.py
index a0df7e6..678724e 100644
--- a/cfg_checker/cfg_check.py
+++ b/cfg_checker/cfg_check.py
@@ -64,11 +64,6 @@
help="Set CLI logging level to DEBUG"
)
parser.add_argument(
- '-f',
- '--file',
- help="HTML filename to save report"
- )
- parser.add_argument(
'-s',
'--sudo',
action='store_true', default=True,
@@ -86,6 +81,21 @@
'report',
help="Report package versions to HTML file"
)
+ pkg_report_parser.add_argument(
+ '--full',
+ metavar='packages_html_filename',
+ help="HTML report will have all of the packages, not just errors"
+ )
+ pkg_report_parser.add_argument(
+ '--html',
+ metavar='packages_html_filename',
+ help="HTML filename to save report"
+ )
+ pkg_report_parser.add_argument(
+ '--csv',
+ metavar='packages_csv_filename',
+ help="CSV filename to save report"
+ )
# networking
net_parser = subparsers.add_parser(
@@ -103,6 +113,12 @@
'report',
help="Generate network check report"
)
+
+ net_report_parser.add_argument(
+ '--html',
+ metavar='network_html_filename',
+ help="HTML filename to save report"
+ )
# reclass
reclass_parser = subparsers.add_parser(
@@ -135,6 +151,12 @@
required=True,
help="Model B <path>. Model name is the folder name"
)
+ reclass_diff_parser.add_argument(
+ '--html',
+ metavar='reclass_html_filename',
+ help="HTML filename to save report"
+ )
+
#parse arguments
diff --git a/cfg_checker/common/const.py b/cfg_checker/common/const.py
index 4142ea7..8ca0d8c 100644
--- a/cfg_checker/common/const.py
+++ b/cfg_checker/common/const.py
@@ -9,8 +9,40 @@
NODE_DOWN = next(_cnt)
NODE_UP = next(_cnt)
+# version const order is important!
+# biggest get shown in report top row
+VERSION_NA = next(_cnt)
+VERSION_OK = next(_cnt)
+VERSION_UP = next(_cnt)
+VERSION_DOWN = next(_cnt)
+VERSION_ERR = next(_cnt)
+
+# action const order is important!
+# biggest get shown in report top row
+ACT_NA = next(_cnt)
+ACT_UPGRADE = next(_cnt)
+ACT_NEED_UP = next(_cnt)
+ACT_NEED_DOWN = next(_cnt)
+ACT_REPO = next(_cnt)
+
del _cnt
+all_actions = {
+ ACT_UPGRADE: "upgrade possible",
+ ACT_NEED_UP: "needs upgrade",
+ ACT_NEED_DOWN: "needs downgrade",
+ ACT_REPO: "needs repo update",
+ ACT_NA: ""
+}
+
+all_statuses = {
+ VERSION_OK: "ok",
+ VERSION_UP: "upgraded",
+ VERSION_DOWN: "downgraded",
+ VERSION_ERR: "error",
+ VERSION_NA: "no status"
+}
+
all_roles_map = {
"apt": "repository",
"bmk": "validation",
diff --git a/cfg_checker/common/settings.py b/cfg_checker/common/settings.py
index 30cc7f2..8d8111c 100644
--- a/cfg_checker/common/settings.py
+++ b/cfg_checker/common/settings.py
@@ -31,6 +31,8 @@
self.date_format = "%Y-%m-%d %H:%M:%S.%f%z"
self.default_tz = "UTC"
+ self.pkg_versions_map = 'versions_map.csv'
+
self.ssh_uses_sudo = False
self.ssh_key = os.environ.get('SSH_KEY', None)
self.ssh_user = os.environ.get('SSH_USER', None)
diff --git a/cfg_checker/helpers/args_utils.py b/cfg_checker/helpers/args_utils.py
index d7b694d..f8453e4 100644
--- a/cfg_checker/helpers/args_utils.py
+++ b/cfg_checker/helpers/args_utils.py
@@ -3,11 +3,20 @@
from cfg_checker.common.exception import ConfigException
-def get_file_arg(args):
- if args.file:
- return args.file
+def get_arg(args, str_arg):
+ _attr = getattr(args, str_arg)
+ if _attr:
+ return _attr
else:
- raise ConfigException("No report filename supplied")
+ _c = args.command if hasattr(args, 'command') else ''
+ _t = args.type if hasattr(args, 'type') else ''
+ raise ConfigException(
+ "Argument '{}' not found executing: mcp_check {} {}".format(
+ str_arg,
+ _c,
+ _t
+ )
+ )
def get_path_arg(path):
@@ -15,3 +24,15 @@
return path
else:
raise ConfigException("'{}' not exists".format(path))
+
+
+def get_report_type_and_filename(args):
+ if args.html or args.csv:
+ if args.html and args.csv:
+ raise ConfigException("Multuple report types not supported")
+ if args.html is not None:
+ return 'html', args.html
+ if args.csv is not None:
+ return 'csv', args.csv
+ else:
+ raise ConfigException("Report type and filename not set")
diff --git a/cfg_checker/helpers/console_utils.py b/cfg_checker/helpers/console_utils.py
new file mode 100644
index 0000000..33e1a39
--- /dev/null
+++ b/cfg_checker/helpers/console_utils.py
@@ -0,0 +1,30 @@
+from time import sleep
+import sys
+
+
+class Progress(object):
+ def __init__(self, max_index, bar_size=21):
+ self.total = max_index
+ # bar size in symbols
+ self.bar_size = bar_size
+
+ def write_progress(self, index, note=''):
+ #calc index and percent values
+ _percent = (100 * index) / self.total
+ _index = (self.bar_size * index) / self.total
+ # clear the line
+ sys.stdout.write('\r')
+ # print new progress
+ _format = "[{:"+str(self.bar_size-1)+"}] {}/{} ({}%) {}"
+ sys.stdout.write(_format.format(
+ '='*_index,
+ index,
+ self.total,
+ _percent,
+ note
+ ))
+ sys.stdout.flush()
+
+ @staticmethod
+ def newline():
+ sys.stdout.write('\n')
diff --git a/cfg_checker/modules/network/__init__.py b/cfg_checker/modules/network/__init__.py
index 8074a71..6217b1a 100644
--- a/cfg_checker/modules/network/__init__.py
+++ b/cfg_checker/modules/network/__init__.py
@@ -3,22 +3,26 @@
from cfg_checker.helpers import args_utils
from cfg_checker.common import logger_cli
+def _prepare_check():
+ _checker_class = checker.NetworkChecker()
+ _checker_class.collect_reclass_networks()
+ _checker_class.collect_network_info()
+ return _checker_class
+
def do_check(args):
- logger_cli.info("# Network check (CLI output)")
- netChecker = checker.NetworkChecker()
- netChecker.collect_reclass_networks()
- netChecker.collect_network_info()
+ logger_cli.info("# Network check to console")
+ netChecker = _prepare_check()
netChecker.print_network_report()
return
def do_report(args):
- logger_cli.info("# Network check (HTML report: '{}')".format(args.file))
- _filename = args_utils.get_file_arg(args)
+ logger_cli.info("# Network report")
- netChecker = checker.NetworkChecker()
- netChecker.collect_network_info()
+ _filename = args_utils.get_arg(args, 'html')
+
+ netChecker = _prepare_check()
netChecker.create_html_report(_filename)
return
diff --git a/cfg_checker/modules/network/checker.py b/cfg_checker/modules/network/checker.py
index 362b877..b0056c8 100644
--- a/cfg_checker/modules/network/checker.py
+++ b/cfg_checker/modules/network/checker.py
@@ -249,6 +249,9 @@
)
_report({
"nodes": self.nodes,
- "diffs": {}
+ "network": {},
+ "mcp_release": self.mcp_release,
+ "openstack_release": self.openstack_release
+
})
logger_cli.info("-> Done")
diff --git a/cfg_checker/modules/packages/__init__.py b/cfg_checker/modules/packages/__init__.py
index 0e2d956..774e674 100644
--- a/cfg_checker/modules/packages/__init__.py
+++ b/cfg_checker/modules/packages/__init__.py
@@ -4,12 +4,12 @@
def do_report(args):
- """Create package versions report
+ """Create package versions report, HTML
:args: - parser arguments
:return: - no return value
"""
- _filename = args_utils.get_file_arg(args)
+ _type, _filename = args_utils.get_report_type_and_filename(args)
# init connection to salt and collect minion data
pChecker = checker.CloudPackageChecker()
@@ -18,4 +18,4 @@
# diff installed and candidates
pChecker.collect_packages()
# report it
- pChecker.create_html_report(_filename)
+ pChecker.create_report(_filename, rtype=_type, full=args.full)
diff --git a/cfg_checker/modules/packages/checker.py b/cfg_checker/modules/packages/checker.py
index 4956a52..8a3456d 100644
--- a/cfg_checker/modules/packages/checker.py
+++ b/cfg_checker/modules/packages/checker.py
@@ -4,14 +4,119 @@
from copy import deepcopy
-from cfg_checker.reports import reporter
+from cfg_checker.common.exception import ConfigException
from cfg_checker.common import utils, const
from cfg_checker.common import config, logger, logger_cli, pkg_dir
from cfg_checker.common import salt_utils
+from cfg_checker.helpers.console_utils import Progress
from cfg_checker.nodes import SaltNodes, node_tmpl
+from cfg_checker.reports import reporter
+
+from versions import PkgVersions, DebianVersion, VersionCmpResult
class CloudPackageChecker(SaltNodes):
+ @staticmethod
+ def presort_packages(all_packages, full=None):
+ logger_cli.info("-> Presorting packages")
+ # labels
+ _data = {}
+ _data = {
+ "cs": {
+ "ok": const.VERSION_OK,
+ "up": const.VERSION_UP,
+ "down": const.VERSION_DOWN,
+ "err": const.VERSION_ERR
+ },
+ "ca": {
+ "na": const.ACT_NA,
+ "up": const.ACT_UPGRADE,
+ "need_up": const.ACT_NEED_UP,
+ "need_down": const.ACT_NEED_DOWN,
+ "repo": const.ACT_REPO
+ }
+ }
+ _data['status_err'] = const.VERSION_ERR
+ _data['status_down'] = const.VERSION_DOWN
+
+ # Presort packages
+ _data['critical'] = {}
+ _data['system'] = {}
+ _data['other'] = {}
+ _data['unlisted'] = {}
+
+ _l = len(all_packages)
+ _progress = Progress(_l)
+ _progress_index = 0
+ # counters
+ _ec = _es = _eo = _eu = 0
+ _dc = _ds = _do = _du = 0
+ while _progress_index < _l:
+ # progress bar
+ _progress_index += 1
+ _progress.write_progress(_progress_index)
+ # sort packages
+ _pn, _val = all_packages.popitem()
+ _c = _val['desc']['component']
+ if full:
+ # Check if this packet has errors
+ # if all is ok -> just skip it
+ _max_status = max(_val['results'].keys())
+ if _max_status <= const.VERSION_OK:
+ _max_action = max(_val['results'][_max_status].keys())
+ if _max_action == const.ACT_NA:
+ # this package do not ha any comments
+ # ...just skip it from report
+ continue
+
+ if len(_c) > 0 and _c == 'unlisted':
+ # not listed package in version lib
+ _data['unlisted'].update({
+ _pn: _val
+ })
+ _eu += _val['results'].keys().count(const.VERSION_ERR)
+ _du += _val['results'].keys().count(const.VERSION_DOWN)
+ # mirantis/critical
+ elif len(_c) > 0 and _c != 'System':
+ # not blank and not system
+ _data['critical'].update({
+ _pn: _val
+ })
+ _ec += _val['results'].keys().count(const.VERSION_ERR)
+ _dc += _val['results'].keys().count(const.VERSION_DOWN)
+ # system
+ elif _c == 'System':
+ _data['system'].update({
+ _pn: _val
+ })
+ _es += _val['results'].keys().count(const.VERSION_ERR)
+ _ds += _val['results'].keys().count(const.VERSION_DOWN)
+ # rest
+ else:
+ _data['other'].update({
+ _pn: _val
+ })
+ _eo += _val['results'].keys().count(const.VERSION_ERR)
+ _do += _val['results'].keys().count(const.VERSION_DOWN)
+
+
+ _progress.newline()
+
+ _data['errors'] = {
+ 'mirantis': _ec,
+ 'system': _es,
+ 'other': _eo,
+ 'unlisted': _eu
+ }
+ _data['downgrades'] = {
+ 'mirantis': _dc,
+ 'system': _ds,
+ 'other': _do,
+ 'unlisted': _du
+ }
+
+ return _data
+
def collect_installed_packages(self):
"""
Collect installed packages on each node
@@ -50,46 +155,115 @@
:return: no return values, all date put to dict in place
"""
+ # Preload OpenStack release versions
+ _desc = PkgVersions()
+
+ logger_cli.info("# Cross-comparing: Installed vs Candidates vs Release")
+ _progress = Progress(len(self.nodes.keys()))
+ _progress_index = 0
+ _total_processed = 0
# Collect packages from all of the nodes in flat dict
- _diff_packages = {}
+ _all_packages = {}
for node_name, node_value in self.nodes.iteritems():
+ _uniq_len = len(_all_packages.keys())
+ _progress_index += 1
+ # progress will jump from node to node
+ # it is very costly operation to execute it for each pkg
+ _progress.write_progress(
+ _progress_index,
+ note="/ {} uniq out of {} packages found".format(
+ _uniq_len,
+ _total_processed
+ )
+ )
for _name, _value in node_value['packages'].iteritems():
- if _name not in _diff_packages:
- _diff_packages[_name] = {}
- _diff_packages[_name]['df_nodes'] = {}
- _diff_packages[_name]['eq_nodes'] = []
-
- # compare packages, mark if equal
- if _value['installed'] != _value['candidate']:
- # Saving compare value so we not do str compare again
- _value['is_equal'] = False
- # add node name to list
- _diff_packages[_name]['df_nodes'][node_name] = {
- 'i': _value['installed'],
- 'c': _value['candidate'],
- 'raw': _value['raw']
+ _total_processed += 1
+ # Parse versions
+ _ver_ins = DebianVersion(_value['installed'])
+ _ver_can = DebianVersion(_value['candidate'])
+
+ # All packages list with version and node list
+ if _name not in _all_packages:
+ # shortcuts for this cloud values
+ _os = self.openstack_release
+ _mcp = self.mcp_release
+ _pkg_desc = {}
+ if _desc[_name]:
+ # shortcut to version library
+ _vers = _desc[_name]['versions']
+ _pkg_desc = _desc[_name]
+ else:
+ # no description - no library :)
+ _vers = {}
+ _pkg_desc = _desc.dummy_desc
+
+ # get specific set for this OS release if present
+ if _os in _vers:
+ _v = _vers[_os]
+ elif 'any' in _vers:
+ _v = _vers['any']
+ else:
+ _v = {}
+ # Finally, get specific version
+ _release = DebianVersion(_v[_mcp] if _mcp in _v else '')
+ # Populate package info
+ _all_packages[_name] = {
+ "desc": _pkg_desc,
+ "results": {},
+ "r": _release,
}
- else:
- # Saving compare value so we not do str compare again
- _value['is_equal'] = True
- _diff_packages[_name]['eq_nodes'].append(node_name)
+
+ _cmp = VersionCmpResult(
+ _ver_ins,
+ _ver_can,
+ _all_packages[_name]['r']
+ )
+
+ # shortcut to results
+ _res = _all_packages[_name]['results']
+ # update status
+ if _cmp.status not in _res:
+ _res[_cmp.status] = {}
+ # update action
+ if _cmp.action not in _res[_cmp.status]:
+ _res[_cmp.status][_cmp.action] = {}
+ # update node
+ if node_name not in _res[_cmp.status][_cmp.action]:
+ _res[_cmp.status][_cmp.action][node_name] = {}
+ # put result
+ _res[_cmp.status][_cmp.action][node_name] = {
+ 'i': _ver_ins,
+ 'c': _ver_can,
+ 'res': _cmp,
+ 'raw': _value['raw']
+ }
- self.diff_packages = _diff_packages
+ self._packages = _all_packages
+ _progress.newline()
+
- def create_html_report(self, filename):
+ def create_report(self, filename, rtype, full=None):
"""
Create static html showing packages diff per node
:return: buff with html
"""
logger_cli.info("# Generating report to '{}'".format(filename))
+ if rtype == 'html':
+ _type = reporter.HTMLPackageCandidates()
+ elif rtype == 'csv':
+ _type = reporter.CSVAllPackages()
+ else:
+ raise ConfigException("Report type not set")
_report = reporter.ReportToFile(
- reporter.HTMLPackageCandidates(),
+ _type,
filename
)
- _report({
+ payload = {
"nodes": self.nodes,
- "rc_diffs": {},
- "pkg_diffs": self.diff_packages
- })
+ "mcp_release": self.mcp_release,
+ "openstack_release": self.openstack_release
+ }
+ payload.update(self.presort_packages(self._packages, full))
+ _report(payload)
logger_cli.info("-> Done")
diff --git a/cfg_checker/modules/packages/versions.py b/cfg_checker/modules/packages/versions.py
new file mode 100644
index 0000000..10f65dc
--- /dev/null
+++ b/cfg_checker/modules/packages/versions.py
@@ -0,0 +1,345 @@
+import csv
+import os
+
+from cfg_checker.common import config, logger, logger_cli, pkg_dir, const
+
+
+class PkgVersions(object):
+ _labels = []
+ _list = {}
+
+ dummy_desc = {
+ "component": "unlisted",
+ "app": "-",
+ "repo": "-",
+ "versions": {}
+ }
+
+ def __init__(self):
+ # preload csv file
+ logger_cli.info("# Preloading MCP release versions")
+ with open(os.path.join(pkg_dir, 'etc', config.pkg_versions_map)) as f:
+ _reader = csv.reader(f, delimiter=',')
+ # load packages
+ for row in _reader:
+ # load release version labels
+ if _reader.line_num == 1:
+ self._labels = [v for v in row[5:]]
+ continue
+ # package_name,component,application_or_service,repo,openstack_release,2018.4.0,2018.11.0,2019.2.0,2019.2.1,2019.2.2
+ # reassign for code readability
+ _pkg = row[0]
+ _component = row[1]
+ _app = row[2]
+ _repo = row[3]
+ # if release cell empty - use keyword 'any'
+ _os_release = row[4] if len(row[4]) > 0 else 'any'
+
+ # prepare versions dict
+ _l = self._labels
+ _versions = {_l[i]:row[5+i] for i in range(0, len(row[5:]))}
+
+ if _pkg in self._list:
+ if _os_release in self._list[_pkg]["versions"]:
+ # all pkg/os_releases should be uniq. If found, latest one used
+ logger_cli.info(
+ "-> WARNING: Duplicate package info found "
+ "'{}' (line {})".format(
+ _pkg,
+ _reader.line_num
+ )
+ )
+ else:
+ # update pkg data in list
+ self._list.update({
+ _pkg: {
+ "component": _component,
+ "app": _app,
+ "repo": _repo,
+ "versions": {}
+ }
+ })
+
+ # and finally, update the versions for this release
+ self._list[_pkg]["versions"].update({
+ _os_release: _versions
+ })
+
+ def __getitem__(self, pkg_name):
+ if pkg_name in self._list:
+ return self._list[pkg_name]
+ else:
+ #return self._dummy_desc
+ return None
+
+
+class DebianVersion(object):
+ epoch = None
+ epoch_status = const.VERSION_NA
+ upstream = None
+ upstream_rev = None
+ upstream_status = const.VERSION_NA
+ debian = None
+ debian_rev = None
+ debian_status = const.VERSION_NA
+
+ status = ""
+ version = ""
+
+ @staticmethod
+ def split_revision(version_fragment):
+ # The symbols are -, +, ~
+ _symbols = ['-', '+', '~']
+ # nums, coz it is faster then regex
+ _chars = [46, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57]
+ _ord_map = [ord(ch) not in _chars for ch in version_fragment]
+ # if there is nothing to extract, return at once
+ if not any([_s in version_fragment for _s in _symbols]) \
+ and not any(_ord_map):
+ # no revisions
+ return version_fragment, ""
+ else:
+ _main = _rev = ""
+ # get indices
+ _indices = []
+ for _s in _symbols:
+ if _s in version_fragment:
+ _indices.append(version_fragment.index(_s))
+ for _s in version_fragment:
+ if ord(_s) not in _chars:
+ _indices.append(version_fragment.index(_s))
+ # sort indices
+ _indices.sort()
+ # extract starting from the lowest one
+ _main = version_fragment[:_indices[0]]
+ _rev = version_fragment[_indices[0]:]
+ return _main, _rev
+
+ def __init__(self, version_string):
+ # save
+ if len(version_string) < 1:
+ self.epoch = None
+ self.upstream = None
+ self.debian = None
+ self.version = 'n/a'
+ return
+ else:
+ # do parse the main versions
+ _v = version_string
+ # colon presence, means epoch present
+ _e = _v.split(':', 1)[0] if ':' in _v else ''
+ # if epoch was there, upstream should be cut
+ _m = _v if ':' not in _v else _v.split(':', 1)[1]
+ # dash presence, means debian present
+ _d = _m.rsplit('-', 1)[1] if '-' in _m else ''
+ # if debian was there, upstream version should be cut
+ _m = _m if '-' not in _m else _m.rsplit('-', 1)[0]
+
+ self.epoch = _e
+ self.upstream, self.upstream_rev = self.split_revision(_m)
+ self.debian, self.debian_rev = self.split_revision(_d)
+ self.version = version_string
+
+ # Following functions is a freestyle python mimic of apt's upstream, enjoy
+ # https://github.com/chaos/apt/blob/master/apt/apt-pkg/deb/debversion.cc#L42
+ # mimic produced in order not to pull any packages or call external code
+ @staticmethod
+ def _cmp_fragment(lhf, rhf):
+ # search for difference
+ # indices
+ _li = _ri = 0
+ # pre-calc len
+ _lL = len(lhf)
+ _rL = len(rhf)
+ # bool for compare found
+ _diff = False
+ while _li < _lL and _ri < _rL:
+ # iterate lists
+ _num = lhf[_li] - rhf[_ri]
+ if _num:
+ return _num
+ _li += 1
+ _ri += 1
+
+ # diff found? lens equal?
+ if not _diff and _lL != _rL:
+ # lens not equal? Longer - later
+ return _lL - _rL
+ else:
+ # equal
+ return 0
+
+ def _cmp_num(self, lf, rf):
+ # split fragments into lists
+ _lhf = lf.split('.') if '.' in lf else list(lf)
+ _rhf = rf.split('.') if '.' in rf else list(rf)
+ # cast them to ints, delete empty strs
+ _lhf = [int(n) for n in _lhf if len(n)]
+ _rhf = [int(n) for n in _rhf if len(n)]
+
+ return self._cmp_fragment(_lhf, _rhf)
+
+ def _cmp_lex(self, lf, rf):
+ # cast each item into its ORD value
+ _lhf = [ord(n) for n in lf]
+ _rhf = [ord(n) for n in rf]
+
+ return self._cmp_fragment(_lhf, _rhf)
+ # end of cmps
+
+ # main part compared using splitted numbers
+ # if equal, revision is compared using lexical comparizon
+ def __lt__(self, v):
+ if self._cmp_num(self.epoch, v.epoch) < 0:
+ return True
+ elif self._cmp_num(self.upstream, v.upstream) < 0:
+ return True
+ elif self._cmp_lex(self.upstream_rev, v.upstream_rev) < 0:
+ return True
+ else:
+ return False
+
+ def __eq__(self, v):
+ # compare all portions
+ _result = []
+ _result.append(self._cmp_num(self.epoch, v.epoch))
+ _result.append(self._cmp_num(self.upstream, v.upstream))
+ _result.append(self._cmp_lex(self.upstream_rev, v.upstream_rev))
+ # if there is any non-zero, its not equal
+ return not any(_result)
+
+ def __gt__(self, v):
+ if self._cmp_num(self.epoch, v.epoch) > 0:
+ return True
+ elif self._cmp_num(self.upstream, v.upstream) > 0:
+ return True
+ elif self._cmp_lex(self.upstream_rev, v.upstream_rev) > 0:
+ return True
+ else:
+ return False
+
+ def update_parts(self, target, status):
+ # updating parts of version statuses
+ if self._cmp_num(self.epoch, target.epoch) != 0:
+ self.epoch_status = status
+ else:
+ self.epoch_status = const.VERSION_OK
+
+ if self._cmp_num(self.upstream, target.upstream) != 0 \
+ or self._cmp_lex(self.upstream_rev, target.upstream_rev) != 0:
+ self.upstream_status = status
+ else:
+ self.upstream_status = const.VERSION_OK
+
+ if self._cmp_lex(self.debian, target.debian) != 0 \
+ or self._cmp_lex(self.debian_rev, target.debian_rev) != 0:
+ self.debian_status = status
+ else:
+ self.debian_status = const.VERSION_OK
+
+
+class VersionCmpResult(object):
+ status = ""
+ action = ""
+
+ source = None
+ target = None
+
+
+ def __init__(self, i, c, r):
+ # compare three versions and write a result
+ self.source = i
+ self.status = const.VERSION_NA
+ self.action = const.ACT_NA
+
+ # Check if there is a release version present
+ if r and len(r.version) > 0 and r.version != 'n/a':
+ # I < C, installed version is older
+ if i < c:
+ self.target = c
+ if i == r:
+ # installed version is equal vs release version
+ self.status = const.VERSION_OK
+ self.action = const.ACT_UPGRADE
+ elif i > r:
+ # installed version is newer vs release version
+ self.status = const.VERSION_UP
+ self.action = const.ACT_UPGRADE
+ elif i < r and r < c:
+ # installed version is older vs release version
+ self.status = const.VERSION_ERR
+ self.action = const.ACT_NEED_UP
+ self.target = r
+ elif i < r and c == r:
+ # installed version is older vs release version
+ self.status = const.VERSION_ERR
+ self.action = const.ACT_NEED_UP
+ self.target = c
+ elif c < r:
+ # installed and repo versions older vs release version
+ self.status = const.VERSION_ERR
+ self.action = const.ACT_REPO
+ # I > C
+ # installed version is newer
+ elif i > c:
+ self.target = c
+ if c == r:
+ # some unknown version installed
+ self.status = const.VERSION_ERR
+ self.action = const.ACT_NEED_DOWN
+ elif c > r:
+ # installed and repo versions newer than release
+ self.status = const.VERSION_UP
+ self.action = const.ACT_NEED_DOWN
+ elif c < r and r < i:
+ # repo is older vs release and both older vs installed
+ self.status = const.VERSION_UP
+ self.action = const.ACT_REPO
+ elif c < r and r == i:
+ # repo is older vs release, but release version installed
+ self.status = const.VERSION_OK
+ self.action = const.ACT_REPO
+ elif i < r:
+ # both repo and installed older vs release, new target
+ self.status = const.VERSION_DOWN
+ self.action = const.ACT_REPO
+ self.target = r
+ # I = C
+ # installed and linked repo is inline,
+ elif i == c:
+ self.target = c
+ if i < r:
+ # both are old, new target
+ self.status = const.VERSION_ERR
+ self.action = const.ACT_REPO
+ self.target = r
+ elif i > r:
+ # both are newer, same target
+ self.status = const.VERSION_UP
+ self.action = const.ACT_NA
+ elif i == r:
+ # all is ok
+ self.status = const.VERSION_OK
+ self.action = const.ACT_NA
+ else:
+ # no release version present
+ self.target = c
+ if i < c:
+ self.status = const.VERSION_OK
+ self.action = const.ACT_UPGRADE
+ elif i > c:
+ self.status = const.VERSION_UP
+ self.action = const.ACT_NEED_DOWN
+ elif i == c:
+ self.status = const.VERSION_OK
+ self.action = const.ACT_NA
+
+ # and we need to update per-part status
+ self.source.update_parts(self.target, self.status)
+
+ @staticmethod
+ def deb_lower(_s, _t):
+ if _t.debian and _t.debian > _s.debian:
+ return True
+ else:
+ return false
diff --git a/cfg_checker/modules/reclass/__init__.py b/cfg_checker/modules/reclass/__init__.py
index 66576b6..0dcf426 100644
--- a/cfg_checker/modules/reclass/__init__.py
+++ b/cfg_checker/modules/reclass/__init__.py
@@ -10,7 +10,9 @@
def do_list(args):
logger_cli.info("# Reclass list")
- _path = args_utils.get_path_arg(args.models_path)
+ _arg_path = args_utils.get_arg(args, 'models_path')
+ logger_cli.info("-> Current path is: {}".format(_arg_path))
+ _path = args_utils.get_path_arg(_arg_path)
logger_cli.info("# ...models path is '{}'".format(args.models_path))
@@ -38,7 +40,7 @@
def do_diff(args):
logger_cli.info("# Reclass comparer (HTML report: '{}'".format(args.file))
- _filename = args_utils.get_file_arg(args)
+ _filename = args_utils.get_arg(args, 'html')
# checking folder params
_model1 = args_utils.get_path_arg(args.model1)
diff --git a/cfg_checker/nodes.py b/cfg_checker/nodes.py
index b2bfd88..776c8b2 100644
--- a/cfg_checker/nodes.py
+++ b/cfg_checker/nodes.py
@@ -22,7 +22,7 @@
logger_cli.info("# Collecting nodes")
# simple salt rest client
self.salt = salt_utils.SaltRemote()
-
+
# Keys for all nodes
# this is not working in scope of 2016.8.3, will overide with list
logger_cli.debug("...collecting node names existing in the cloud")
@@ -82,6 +82,22 @@
self.nodes
)
)
+ # get master node fqdn
+ self.master_node = filter(
+ lambda nd: self.nodes[nd]['role'] == const.all_roles_map['cfg'],
+ self.nodes
+ )[0]
+
+ # OpenStack versions
+ self.mcp_release = self.salt.pillar_get(
+ self.master_node,
+ "_param:apt_mk_version"
+ )[self.master_node]
+ self.openstack_release = self.salt.pillar_get(
+ self.master_node,
+ "_param:openstack_version"
+ )[self.master_node]
+
def skip_node(self, node):
# Add node to skip list
diff --git a/cfg_checker/reports/reporter.py b/cfg_checker/reports/reporter.py
index e1d6b6f..377c061 100644
--- a/cfg_checker/reports/reporter.py
+++ b/cfg_checker/reports/reporter.py
@@ -1,35 +1,82 @@
-import jinja2
-import six
import abc
+import jinja2
import os
+import six
+import time
from cfg_checker.common import const
+from cfg_checker.common import logger, logger_cli
+from cfg_checker.helpers.console_utils import Progress
pkg_dir = os.path.dirname(__file__)
pkg_dir = os.path.join(pkg_dir, os.pardir, os.pardir)
pkg_dir = os.path.normpath(pkg_dir)
-def shortname(node_fqdn):
- # form shortname out of node fqdn
- return node_fqdn.split(".", 1)[0]
-
-
-def is_equal(pkg_dict):
- # compare versions of given package
- return pkg_dict['installed'] == pkg_dict['candidate']
-
-
-def is_active(node_dict):
- # check node status in node dict
- return node_dict['status'] == const.NODE_UP
-
-
def line_breaks(text):
# replace python linebreaks with html breaks
return text.replace("\n", "<br />")
+def get_sorted_keys(td):
+ # detect if we can sort by desc
+ # Yes, this is slow, but bullet-proof from empty desc
+ _desc = all([bool(td[k]['desc']) for k in td.keys()])
+ # Get sorted list
+ if not _desc:
+ return sorted(td.keys())
+ else:
+ return sorted(
+ td.keys(),
+ key=lambda k: (
+ td[k]['desc']['component'],
+ td[k]['desc']['app'],
+ k
+ )
+ )
+
+
+def get_max(_list):
+ return sorted(_list)[-1]
+
+
+def make_action_label(act):
+ _act_labels = {
+ const.ACT_UPGRADE: "Upgrade possible",
+ const.ACT_NEED_UP: "Needs upgrade",
+ const.ACT_NEED_DOWN: "Needs downgrade",
+ const.ACT_REPO: "Needs repo update",
+ const.ACT_NA: ""
+ }
+ return _act_labels[act]
+
+
+def make_action_class(act):
+ _act_classes = {
+ const.ACT_UPGRADE: "possible",
+ const.ACT_NEED_UP: "needs_up",
+ const.ACT_NEED_DOWN: "needs_down",
+ const.ACT_REPO: "needs_repo",
+ const.ACT_NA: ""
+ }
+ return _act_classes[act]
+
+
+def make_status_label(sts):
+ _status_labels = {
+ const.VERSION_OK: "OK",
+ const.VERSION_UP: "Upgraded",
+ const.VERSION_DOWN: "Downgraded",
+ const.VERSION_ERR: "ERROR",
+ const.VERSION_NA: "N/A"
+ }
+ return _status_labels[sts]
+
+
+def make_status_class(sts):
+ return const.all_statuses[sts]
+
+
@six.add_metaclass(abc.ABCMeta)
class _Base(object):
def __init__(self):
@@ -59,14 +106,9 @@
def __call__(self, payload):
# init data structures
data = self.common_data()
- # payload should have pre-sorted structure
- # system, nodes, clusters, and the rest in other
- data.update({
- "nodes": payload['nodes'],
- "rc_diffs": payload['rc_diffs'],
- "pkg_diffs": payload['pkg_diffs'],
- "tabs": {}
- })
+ # payload should have pre-sorted structure according to report called
+ # nodes, openstack_release, mcp_release, etc...
+ data.update(payload)
# add template specific data
self._extend_data(data)
@@ -75,83 +117,40 @@
self._count_totals(data)
# specific filters
- self.jinja2_env.filters['shortname'] = shortname
- self.jinja2_env.filters['is_equal'] = is_equal
- self.jinja2_env.filters['is_active'] = is_active
self.jinja2_env.filters['linebreaks'] = line_breaks
+ self.jinja2_env.filters['get_max'] = get_max
+
+ self.jinja2_env.filters['get_sorted_keys'] = get_sorted_keys
+ self.jinja2_env.filters['make_status_label'] = make_status_label
+ self.jinja2_env.filters['make_status_class'] = make_status_class
+ self.jinja2_env.filters['make_action_label'] = make_action_label
+ self.jinja2_env.filters['make_action_class'] = make_action_class
# render!
+ logger_cli.info("-> Using template: {}".format(self.tmpl))
tmpl = self.jinja2_env.get_template(self.tmpl)
+ logger_cli.info("-> Rendering")
return tmpl.render(data)
def common_data(self):
return {
'counters': {},
- 'salt_info': {}
+ 'salt_info': {},
+ 'gen_date': time.strftime("%m/%d/%Y %H:%M:%S")
}
def _extend_data(self, data):
pass
-# Package versions report
+# HTML Package versions report
+class CSVAllPackages(_TMPLBase):
+ tmpl = "pkg_versions_csv.j2"
+
+
+# HTML Package versions report
class HTMLPackageCandidates(_TMPLBase):
- tmpl = "pkg_versions_tmpl.j2"
-
- @staticmethod
- def is_fail_uniq(p_dict, p_name, nodes, node_name):
- # look up package fail for nodes with similar role
- _tgroup = nodes[node_name]['node_group']
- # filter all nodes with the same role
- _nodes_list = filter(
- lambda nd: nodes[nd]['node_group'] == _tgroup and nd != node_name,
- nodes
- )
- # lookup same package
- _fail_uniq = False
- for _node_name in _nodes_list:
- # check if there is a package present on node
- _nd = nodes[_node_name]['packages']
- if p_name not in _nd:
- continue
- # if both backages has same version and differ from candidate
- if p_dict['candidate'] == _nd[p_name]['candidate'] \
- and _nd[p_name]['candidate'] == _nd[p_name]['installed']:
- # it is not uniq, mark and break
- _fail_uniq = True
- return _fail_uniq
-
- def _extend_data(self, data):
- # Count values on per-node basis
- for key, value in data['nodes'].iteritems():
- # count differences
- data['counters'][key] = {}
- data['counters'][key]['packages'] = len(value['packages'].keys())
- data['counters'][key]['package_diff'] = 0
- data['counters'][key]['package_eq'] = 0
-
- # Lookup if this fail is uniq for this node
- for pkg_name, pkg_value in value['packages'].iteritems():
- if pkg_value['is_equal']:
- pkg_value['fail_uniq'] = False
- data['counters'][key]['package_eq'] += 1
- else:
- pkg_value['fail_uniq'] = self.is_fail_uniq(
- pkg_value,
- pkg_name,
- data['nodes'],
- key
- )
- data['counters'][key]['package_diff'] += 1
-
- # Count values on all-diffs basis
- for key, value in data['pkg_diffs'].iteritems():
- data['counters'][key] = {}
- data['counters'][key]['df_nodes'] = len(value['df_nodes'].keys())
- data['counters'][key]['eq_nodes'] = len(value['eq_nodes'])
-
- # Save all packages counter
- data['counters']['total_packages'] = data['pkg_diffs'].keys()
+ tmpl = "pkg_versions_html.j2"
# Package versions report
@@ -171,10 +170,6 @@
class HTMLNetworkReport(_TMPLBase):
tmpl = "network_check_tmpl.j2"
- def _extend_data(self, data):
-
- return
-
class ReportToFile(object):
def __init__(self, report, target):
diff --git a/etc/versions_map.csv b/etc/versions_map.csv
new file mode 100644
index 0000000..21b0e3b
--- /dev/null
+++ b/etc/versions_map.csv
@@ -0,0 +1,1491 @@
+package_name,component,application_or_service,repo,openstack_release,2018.4.0,2018.11.0,2019.2.0,2019.2.1,2019.2.2
+accountsservice,,,,,,,,,
+acl,,,,,,,,,
+acpid,,,,,,,,,
+adduser,,,,,,,,,
+alembic,,,,,,,,,
+amd64-microcode,,,,,,,,,
+apache2,System,WebCGI,,,,,,,
+apache2-bin,System,WebCGI,,,,,,,
+apache2-data,System,WebCGI,,,,,,,
+apache2-utils,System,WebCGI,,,,,,,
+apparmor,System,Virtualization,,,,,,,
+apport,,,,,,,,,
+apport-symptoms,,,,,,,,,
+apt,DriveTrain,Aptly,mirantis,,,,,,
+apt-transport-https,DriveTrain,Aptly,mirantis,,,,,,
+apt-utils,DriveTrain,Aptly,mirantis,,,,,,
+archdetect-deb,,,,,,,,,
+at,,,,,,,,,
+attr,,,,,,,,,
+augeas-lenses,,,,,,,,,
+authbind,,,,,,,,,
+avahi-daemon,,,,,,,,,
+avahi-utils,,,,,,,,,
+backupninja,,,,,,,,,
+base-files,,,,,,,,,
+base-passwd,,,,,,,,,
+bash,System,Shell,,,,,,,
+bash-completion,System,Shell,,,,,,,
+bc,,,,,,,,,
+bcache-tools,,,,,,,,,
+bind9,,,,,,,,,
+bind9-host,,,,,,,,,
+bind9utils,,,,,,,,,
+binutils,,,,,,,,,
+bridge-utils,,,,,,,,,
+bsd-mailx,,,,,,,,,
+bsdmainutils,,,,,,,,,
+bsdutils,,,,,,,,,
+btrfs-tools,,,,,,,,,
+busybox-initramfs,,,,,,,,,
+busybox-static,,,,,,,,,
+byobu,System,Shell,,,,,,,
+bzip2,,,,,,,,,
+ca-certificates,System,SSL,,,,,,,
+ca-certificates-java,System,SSL,,,,,,,
+ceph-base,Distributed storage,Ceph,mirantis,,,12.2.8-1~u16.04+mcp142,12.2.8-1~u16.04+mcp142,,
+ceph-common,Distributed storage,Ceph,mirantis,,,12.2.8-1~u16.04+mcp142,12.2.8-1~u16.04+mcp142,,
+ceph-mgr,Distributed storage,Ceph,mirantis,,,12.2.8-1~u16.04+mcp142,12.2.8-1~u16.04+mcp142,,
+ceph-mon,Distributed storage,Ceph,mirantis,,,12.2.8-1~u16.04+mcp142,12.2.8-1~u16.04+mcp142,,
+ceph-osd,Distributed storage,Ceph,mirantis,,,12.2.8-1~u16.04+mcp142,12.2.8-1~u16.04+mcp142,,
+cinder-api,OpenStack,Cinder,mirantis,Pike,,2:11.1.0-1~u16.04+mcp59,,,
+cinder-backup,OpenStack,Cinder,mirantis,Pike,,2:11.1.0-1~u16.04+mcp59,,,
+cinder-api,OpenStack,Cinder,mirantis,,,,,,
+cinder-backup,OpenStack,Cinder,mirantis,,,,,,
+cinder-common,OpenStack,Cinder,mirantis,Queens,,12.0.4-2~u16.04+mcp69,2:12.0.4-2~u16.04+mcp96 [5],,
+cinder-scheduler,OpenStack,Cinder,mirantis,Queens,,12.0.4-2~u16.04+mcp69,2:12.0.4-2~u16.04+mcp96 [5],,
+cinder-volume,OpenStack,Cinder,mirantis,Queens,,12.0.4-2~u16.04+mcp69,2:12.0.4-2~u16.04+mcp96 [5],,
+cloud-guest-utils,,,,,,,,,
+cloud-initramfs-copymods,,,,,,,,,
+cloud-initramfs-dyn-netconf,,,,,,,,,
+command-not-found,,,,,,,,,
+command-not-found-data,,,,,,,,,
+conntrack,,,,,,,,,
+console-setup,,,,,,,,,
+console-setup-linux,,,,,,,,,
+coreutils,,,,,,,,,
+cpio,,,,,,,,,
+crda,,,,,,,,,
+cron,,,,,,,,,
+cryptsetup,,,,,,,,,
+cryptsetup-bin,,,,,,,,,
+curl,,,,,,,,,
+curtin-common,,,,,,,,,
+daemon,,,,,,,,,
+dash,,,,,,,,,
+dbconfig-common,,,,,,,,,
+dbconfig-pgsql,,,,,,,,,
+dbus,,,,,,,,,
+dctrl-tools,,,,,,,,,
+debconf,,,,,,,,,
+debconf-i18n,,,,,,,,,
+debconf-utils,,,,,,,,,
+debianutils,,,,,,,,,
+debootstrap,,,,,,,,,
+default-jre-headless,,,,,,,,,
+dh-python,,,,,,,,,
+dialog,,,,,,,,,
+diffutils,,,,,,,,,
+distro-info,,,,,,,,,
+distro-info-data,,,,,,,,,
+dmeventd,,,,,,,,,
+dmidecode,,,,,,,,,
+dmsetup,,,,,,,,,
+dns-root-data,,,,,,,,,
+dnsmasq-base,System,Networking,,,,,,,
+dnsmasq-utils,System,Networking,,,,,,,
+dnsutils,System,Networking,,,,,,,
+docker-ce,System,Docker,mirror,,,18.06.1,5:18.09.0~3-0~ubuntu-xenial,,
+docutils-common,,,,,,,,,
+dosfstools,,,,,,,,,
+dpkg,System,Packaging,,,,,,,
+dpkg-dev,System,Packaging,,,,,,,
+e2fslibs,,,,,,,,,
+e2fsprogs,,,,,,,,,
+eatmydata,,,,,,,,,
+ebtables,,,,,,,,,
+ed,,,,,,,,,
+eject,,,,,,,,,
+elasticsearch,StackLight LMA,Elasticsearch,mirror,,,5.6.12,6.5.2,,
+elasticsearch-curator,StackLight LMA,Elasticsearch,,,,,,,
+erlang-asn1,System,Erlang,,,,,,,
+erlang-base-hipe,System,Erlang,,,,,,,
+erlang-corba,System,Erlang,,,,,,,
+erlang-crypto,System,Erlang,,,,,,,
+erlang-diameter,System,Erlang,,,,,,,
+erlang-edoc,System,Erlang,,,,,,,
+erlang-eldap,System,Erlang,,,,,,,
+erlang-erl-docgen,System,Erlang,,,,,,,
+erlang-eunit,System,Erlang,,,,,,,
+erlang-ic,System,Erlang,,,,,,,
+erlang-inets,System,Erlang,,,,,,,
+erlang-mnesia,System,Erlang,,,,,,,
+erlang-nox,System,Erlang,,,,,,,
+erlang-odbc,System,Erlang,,,,,,,
+erlang-os-mon,System,Erlang,,,,,,,
+erlang-parsetools,System,Erlang,,,,,,,
+erlang-public-key,System,Erlang,,,,,,,
+erlang-runtime-tools,System,Erlang,,,,,,,
+erlang-snmp,System,Erlang,,,,,,,
+erlang-ssh,System,Erlang,,,,,,,
+erlang-ssl,System,Erlang,,,,,,,
+erlang-syntax-tools,System,Erlang,,,,,,,
+erlang-tools,System,Erlang,,,,,,,
+erlang-xmerl,System,Erlang,,,,,,,
+ethtool,,,,,,,,,
+extlinux,,,,,,,,,
+fcgiwrap,,,,,,,,,
+file,,,,,,,,,
+findutils,,,,,,,,,
+fontconfig,,,,,,,,,
+fontconfig-config,,,,,,,,,
+fonts-dejavu-core,,,,,,,,,
+fonts-font-awesome,,,,,,,,,
+fonts-lato,,,,,,,,,
+fonts-materialdesignicons-webfont,,,,,,,,,
+fonts-roboto-fontface,,,,,,,,,
+fonts-ubuntu-font-family-console,,,,,,,,,
+formencode-i18n,,,,,,,,,
+freeipmi-common,,,,,,,,,
+freeipmi-tools,,,,,,,,,
+friendly-recovery,,,,,,,,,
+ftp,,,,,,,,,
+fuse,,,,,,,,,
+galera-3,System,Galera,mirror,,,25.3.14,25.3.14,,
+gawk,,,,,,,,,
+gcc-5-base,System,Compilers,,,,,,,
+gcc-6-base,System,Compilers,,,,,,,
+gdb,,,,,,,,,
+gdisk,,,,,,,,,
+genisoimage,,,,,,,,,
+geoip-database,,,,,,,,,
+gettext-base,,,,,,,,,
+gir1.2-glib-2.0,,,,,,,,,
+git,System,Git,mirror,,,2.7.4,2.7.4,,
+git-core,System,Git,mirror,,,2.7.4,2.7.4,,
+git-man,System,Git,mirror,,,2.7.4,2.7.4,,
+glance,OpenStack,Glance,mirantis,Queens,,16.0.1-2~u16.04+mcp21,2:16.0.1-2~u16.04+mcp23,,
+glance-api,OpenStack,Glance,mirantis,Queens,,16.0.1-2~u16.04+mcp21,2:16.0.1-2~u16.04+mcp23,,
+glance-common,OpenStack,Glance,mirantis,Queens,,16.0.1-2~u16.04+mcp21,2:16.0.1-2~u16.04+mcp23,,
+glance-registry,OpenStack,Glance,mirantis,Queens,,16.0.1-2~u16.04+mcp21,2:16.0.1-2~u16.04+mcp23,,
+glance-store-common,OpenStack,Glance,,,,,,,
+glusterfs-client,System,GlusterFS,mirror,,,3.8.15,3.8.15,,
+glusterfs-common,System,GlusterFS,mirror,,,3.8.15,3.8.15,,
+glusterfs-server,System,GlusterFS,mirror,,,3.8.15,3.8.15,,
+gnupg,,,,,,,,,
+gpgv,,,,,,,,,
+grep,,,,,,,,,
+groff-base,,,,,,,,,
+grub-common,,,,,,,,,
+grub-gfxpayload-lists,,,,,,,,,
+grub-legacy-ec2,,,,,,,,,
+grub-pc,,,,,,,,,
+grub-pc-bin,,,,,,,,,
+grub2-common,,,,,,,,,
+gzip,,,,,,,,,
+haproxy,System,HAProxy,mirror,,,1.6.3,1.6.3,,
+haveged,,,,,,,,,
+hdparm,,,,,,,,,
+heat-api,OpenStack,Heat,mirantis,Queens,,10.0.2-1.0~u16.04+mcp37,1:10.0.2-1.0~u16.04+mcp54 [5],,
+heat-api-cfn,OpenStack,Heat,mirantis,Queens,,10.0.2-1.0~u16.04+mcp37,1:10.0.2-1.0~u16.04+mcp54 [5],,
+heat-common,OpenStack,Heat,mirantis,Queens,,10.0.2-1.0~u16.04+mcp37,1:10.0.2-1.0~u16.04+mcp54 [5],,
+heat-engine,OpenStack,Heat,mirantis,Queens,,10.0.2-1.0~u16.04+mcp37,1:10.0.2-1.0~u16.04+mcp54 [5],,
+hostname,,,,,,,,,
+htop,,,,,,,,,
+ieee-data,,,,,,,,,
+ifenslave,,,,,,,,,
+ifenslave-2.6,,,,,,,,,
+ifupdown,,,,,,,,,
+influxdb-relay,,,,,,,,,
+info,,,,,,,,,
+init,,,,,,,,,
+init-system-helpers,,,,,,,,,
+initramfs-tools,,,,,,,,,
+initramfs-tools-bin,,,,,,,,,
+initramfs-tools-core,,,,,,,,,
+initscripts,,,,,,,,,
+insserv,,,,,,,,,
+install-info,,,,,,,,,
+intel-microcode,,,,,,,,,
+iperf,,,,,,,,,
+iperf3,,,,,,,,,
+ipmitool,,,,,,,,,
+iproute2,,,,,,,,,
+ipset,,,,,,,,,
+iptables,System,Firewall,,,,,,,
+iptables-persistent,System,Firewall,,,,,,,
+iputils-arping,,,,,,,,,
+iputils-ping,,,,,,,,,
+iputils-tracepath,,,,,,,,,
+ipxe-qemu,,,,,,,,,
+ipxe-qemu-256k-compat-efi-roms,,,,,,,,,
+irqbalance,,,,,,,,,
+isc-dhcp-client,,,,,,,,,
+isc-dhcp-common,,,,,,,,,
+isc-dhcp-server,,,,,,,,,
+isdct,,,,,,,,,
+iso-codes,,,,,,,,,
+iucode-tool,,,,,,,,,
+iw,,,,,,,,,
+java-common,,,,,,,,,
+javascript-common,,,,,,,,,
+jeepyb,,,,,,,,,
+jenkins,,,,,,,,,
+jq,,,,,,,,,
+kbd,,,,,,,,,
+keepalived,,,,,,,,,
+keyboard-configuration,,,,,,,,,
+keystone,OpenStack,Keystone,mirantis,Queens,,13.0.1-3~u16.04+mcp18,2:13.0.2-3~u16.04+mcp15,,
+kibana,StackLight LMA,Kibana,mirror,,,5.6.12,6.5.2,,
+klibc-utils,,,,,,,,,
+kmod,,,,,,,,,
+kpartx,,,,,,,,,
+krb5-locales,,,,,,,,,
+language-selector-common,,,,,,,,,
+ldap-utils,,,,,,,,,
+ledmon,,,,,,,,,
+less,,,,,,,,,
+libaccountsservice0,,,,,,,,,
+libacl1,,,,,,,,,
+libacl1-dev,,,,,,,,,
+libaio1,,,,,,,,,
+libapache2-mod-wsgi,,,,,,,,,
+libapparmor-perl,System,Virtualization,,,,,,,
+libapparmor1,System,Virtualization,,,,,,,
+libapr1,,,,,,,,,
+libaprutil1,,,,,,,,,
+libaprutil1-dbd-sqlite3,,,,,,,,,
+libaprutil1-ldap,,,,,,,,,
+libapt-inst2.0,,,,,,,,,
+libapt-pkg5.0,,,,,,,,,
+libasn1-8-heimdal,,,,,,,,,
+libasound2,,,,,,,,,
+libasound2-data,,,,,,,,,
+libasprintf0v5,,,,,,,,,
+libasyncns0,,,,,,,,,
+libatk1.0-0,,,,,,,,,
+libatk1.0-data,,,,,,,,,
+libatm1,,,,,,,,,
+libattr1,,,,,,,,,
+libattr1-dev,,,,,,,,,
+libaudit-common,,,,,,,,,
+libaudit1,,,,,,,,,
+libaugeas0,,,,,,,,,
+libavahi-client3,,,,,,,,,
+libavahi-common-data,,,,,,,,,
+libavahi-common3,,,,,,,,,
+libavahi-core7,,,,,,,,,
+libbabeltrace-ctf1,,,,,,,,,
+libbabeltrace1,,,,,,,,,
+libbind9-140,,,,,,,,,
+libblas-common,,,,,,,,,
+libblas3,,,,,,,,,
+libblkid1,,,,,,,,,
+libbluetooth3,,,,,,,,,
+libboost-filesystem1.58.0,,,,,,,,,
+libboost-iostreams1.58.0,,,,,,,,,
+libboost-program-options1.58.0,,,,,,,,,
+libboost-random1.58.0,,,,,,,,,
+libboost-system1.58.0,,,,,,,,,
+libboost-thread1.58.0,,,,,,,,,
+libbrlapi0.6,,,,,,,,,
+libbsd0,,,,,,,,,
+libbz2-1.0,,,,,,,,,
+libc-bin,,,,,,,,,
+libc-dev-bin,,,,,,,,,
+libc6,,,,,,,,,
+libc6-dev,,,,,,,,,
+libcaca0,,,,,,,,,
+libcacard0,,,,,,,,,
+libcairo2,,,,,,,,,
+libcap-ng0,,,,,,,,,
+libcap2,,,,,,,,,
+libcap2-bin,,,,,,,,,
+libcephfs2,Distributed storage,Ceph,mirantis,,,12.2.8-1~u16.04+mcp142,12.2.8-1~u16.04+mcp142,,
+libcomerr2,,,,,,,,,
+libconfig-general-perl,,,,,,,,,
+libcryptsetup4,,,,,,,,,
+libcups2,,,,,,,,,
+libcurl3,,,,,,,,,
+libcurl3-gnutls,,,,,,,,,
+libdaemon0,,,,,,,,,
+libdatrie1,,,,,,,,,
+libdb5.3,,,,,,,,,
+libdbd-mysql,,,,,,,,,
+libdbd-mysql-perl,,,,,,,,,
+libdbi-perl,,,,,,,,,
+libdbi1,,,,,,,,,
+libdbus-1-3,,,,,,,,,
+libdbus-glib-1-2,,,,,,,,,
+libdebconfclient0,,,,,,,,,
+libdebian-installer4,,,,,,,,,
+libdevmapper-event1.02.1,,,,,,,,,
+libdevmapper1.02.1,,,,,,,,,
+libdns-export162,,,,,,,,,
+libdns162,,,,,,,,,
+libdpkg-perl,,,,,,,,,
+libdrm-amdgpu1,,,,,,,,,
+libdrm-common,,,,,,,,,
+libdrm-intel1,,,,,,,,,
+libdrm-nouveau2,,,,,,,,,
+libdrm-radeon1,,,,,,,,,
+libdrm2,,,,,,,,,
+libdumbnet1,,,,,,,,,
+libeatmydata1,,,,,,,,,
+libecap3,,,,,,,,,
+libedit2,,,,,,,,,
+libelf1,,,,,,,,,
+liberror-perl,,,,,,,,,
+libestr0,,,,,,,,,
+libev4,,,,,,,,,
+libevent-2.0-5,,,,,,,,,
+libexpat1,,,,,,,,,
+libfcgi0ldbl,,,,,,,,,
+libfdisk1,,,,,,,,,
+libfdt1,,,,,,,,,
+libffi6,,,,,,,,,
+libflac8,,,,,,,,,
+libfontconfig1,,,,,,,,,
+libfreeipmi16,,,,,,,,,
+libfreetype6,,,,,,,,,
+libfribidi0,,,,,,,,,
+libfuse2,,,,,,,,,
+libgcc1,,,,,,,,,
+libgcrypt20,,,,,,,,,
+libgd3,,,,,,,,,
+libgdbm3,,,,,,,,,
+libgdk-pixbuf2.0-0,,,,,,,,,
+libgdk-pixbuf2.0-common,,,,,,,,,
+libgeoip1,,,,,,,,,
+libgfortran3,,,,,,,,,
+libgif7,,,,,,,,,
+libgirepository-1.0-1,,,,,,,,,
+libgl1-mesa-dri,,,,,,,,,
+libgl1-mesa-glx,,,,,,,,,
+libglapi-mesa,,,,,,,,,
+libglib2.0-0,,,,,,,,,
+libglib2.0-data,,,,,,,,,
+libgmp10,,,,,,,,,
+libgnutls-openssl27,,,,,,,,,
+libgnutls30,,,,,,,,,
+libgoogle-perftools4,,,,,,,,,
+libgpg-error0,,,,,,,,,
+libgpm2,,,,,,,,,
+libgraphite2-3,,,,,,,,,
+libgssapi-krb5-2,,,,,,,,,
+libgssapi3-heimdal,,,,,,,,,
+libgtk2.0-0,,,,,,,,,
+libgtk2.0-common,,,,,,,,,
+libguestfs0,,,,,,,,,
+libharfbuzz0b,,,,,,,,,
+libhavege1,,,,,,,,,
+libhcrypto4-heimdal,,,,,,,,,
+libheimbase1-heimdal,,,,,,,,,
+libheimntlm0-heimdal,,,,,,,,,
+libhivex0,,,,,,,,,
+libhogweed4,,,,,,,,,
+libhx509-5-heimdal,,,,,,,,,
+libibverbs1,,,,,,,,,
+libicu55,,,,,,,,,
+libidn11,,,,,,,,,
+libiperf0,,,,,,,,,
+libipmiconsole2,,,,,,,,,
+libipmidetect0,,,,,,,,,
+libipset3,,,,,,,,,
+libirs-export141,,,,,,,,,
+libirs141,,,,,,,,,
+libisc-export160,,,,,,,,,
+libisc160,,,,,,,,,
+libisccc140,,,,,,,,,
+libisccfg-export140,,,,,,,,,
+libisccfg140,,,,,,,,,
+libiscsi2,,,,,,,,,
+libjansson4,,,,,,,,,
+libjbig0,,,,,,,,,
+libjpeg-turbo8,,,,,,,,,
+libjpeg8,,,,,,,,,
+libjs-angular-file-upload,System,Web,,,,,,,
+libjs-angular-gettext,System,Web,,,,,,,
+libjs-angularjs,System,Web,,,,,,,
+libjs-angularjs-smart-table,System,Web,,,,,,,
+libjs-bootswatch,System,Web,,,,,,,
+libjs-d3,System,Web,,,,,,,
+libjs-jquery,System,Web,,,,,,,
+libjs-jquery-cookie,System,Web,,,,,,,
+libjs-jquery-metadata,System,Web,,,,,,,
+libjs-jquery-tablesorter,System,Web,,,,,,,
+libjs-jquery-ui,System,Web,,,,,,,
+libjs-jquery.quicksearch,System,Web,,,,,,,
+libjs-jsencrypt,System,Web,,,,,,,
+libjs-lrdragndrop,System,Web,,,,,,,
+libjs-magic-search,System,Web,,,,,,,
+libjs-modernizr,System,Web,,,,,,,
+libjs-rickshaw,System,Web,,,,,,,
+libjs-sphinxdoc,System,Web,,,,,,,
+libjs-spin.js,System,Web,,,,,,,
+libjs-swfobject,System,Web,,,,,,,
+libjs-term.js,System,Web,,,,,,,
+libjs-twitter-bootstrap,System,Web,,,,,,,
+libjs-twitter-bootstrap-datepicker,System,Web,,,,,,,
+libjs-underscore,System,Web,,,,,,,
+libjs-yui3-common,System,Web,,,,,,,
+libjs-yui3-full,System,Web,,,,,,,
+libjs-yui3-min,System,Web,,,,,,,
+libjson-c2,,,,,,,,,
+libk5crypto3,,,,,,,,,
+libkeyutils1,,,,,,,,,
+libklibc,,,,,,,,,
+libkmod2,,,,,,,,,
+libkrb5-26-heimdal,,,,,,,,,
+libkrb5-3,,,,,,,,,
+libkrb5support0,,,,,,,,,
+liblapack3,,,,,,,,,
+liblcms2-2,,,,,,,,,
+libldap-2.4-2,,,,,,,,,
+libleveldb1v5,,,,,,,,,
+libllvm6.0,,,,,,,,,
+liblocale-gettext-perl,,,,,,,,,
+liblockfile-bin,,,,,,,,,
+liblockfile1,,,,,,,,,
+libltdl7,,,,,,,,,
+liblttng-ust-ctl2,,,,,,,,,
+liblttng-ust0,,,,,,,,,
+liblua5.1-0,,,,,,,,,
+liblua5.2-0,,,,,,,,,
+liblua5.3-0,,,,,,,,,
+liblvm2app2.2,,,,,,,,,
+liblvm2cmd2.02,,,,,,,,,
+liblwres141,,,,,,,,,
+liblxc1,,,,,,,,,
+liblz4-1,,,,,,,,,
+liblzma5,,,,,,,,,
+liblzo2-2,,,,,,,,,
+libmagic1,,,,,,,,,
+libmnl0,,,,,,,,,
+libmount1,,,,,,,,,
+libmpdec2,,,,,,,,,
+libmpfr4,,,,,,,,,
+libmspack0,,,,,,,,,
+libmysqlclient-dev,,,,,,,,,
+libmysqlclient20,,,,,,,,,
+libncurses5,,,,,,,,,
+libncursesw5,,,,,,,,,
+libnetcf1,,,,,,,,,
+libnetfilter-conntrack3,,,,,,,,,
+libnettle6,,,,,,,,,
+libnewt0.52,,,,,,,,,
+libnfnetlink0,,,,,,,,,
+libnih1,,,,,,,,,
+libnl-3-200,,,,,,,,,
+libnl-genl-3-200,,,,,,,,,
+libnl-route-3-200,,,,,,,,,
+libnspr4,,,,,,,,,
+libnss3,,,,,,,,,
+libnss3-nssdb,,,,,,,,,
+libnuma1,,,,,,,,,
+libodbc1,,,,,,,,,
+libogg0,,,,,,,,,
+libonig2,,,,,,,,,
+libopenipmi0,,,,,,,,,
+libopts25,,,,,,,,,
+libopus0,,,,,,,,,
+libp11-kit0,,,,,,,,,
+libpam-modules,,,,,,,,,
+libpam-modules-bin,,,,,,,,,
+libpam-runtime,,,,,,,,,
+libpam-systemd,,,,,,,,,
+libpam0g,,,,,,,,,
+libpango-1.0-0,,,,,,,,,
+libpangocairo-1.0-0,,,,,,,,,
+libpangoft2-1.0-0,,,,,,,,,
+libparted2,,,,,,,,,
+libpcap0.8,,,,,,,,,
+libpci3,,,,,,,,,
+libpciaccess0,,,,,,,,,
+libpcre3,,,,,,,,,
+libpcrecpp0v5,,,,,,,,,
+libpcsclite1,,,,,,,,,
+libperl5.22,,,,,,,,,
+libpipeline1,,,,,,,,,
+libpixman-1-0,,,,,,,,,
+libplymouth4,,,,,,,,,
+libpng12-0,,,,,,,,,
+libpolkit-agent-1-0,,,,,,,,,
+libpolkit-backend-1-0,,,,,,,,,
+libpolkit-gobject-1-0,,,,,,,,,
+libpopt0,,,,,,,,,
+libpq5,,,,,,,,,
+libprocps4,,,,,,,,,
+libpulse0,,,,,,,,,
+libpython-stdlib,System,Python,,,,,,,
+libpython2.7,System,Python,,,,,,,
+libpython2.7-minimal,System,Python,,,,,,,
+libpython2.7-stdlib,System,Python,,,,,,,
+libpython3-stdlib,System,Python,,,,,,,
+libpython3.5,System,Python,,,,,,,
+libpython3.5-minimal,System,Python,,,,,,,
+libpython3.5-stdlib,System,Python,,,,,,,
+libquadmath0,,,,,,,,,
+librados2,Distributed storage,Ceph,mirantis,,,12.2.8-1~u16.04+mcp142,12.2.8-1~u16.04+mcp142,,
+libradosstriper1,Distributed storage,Ceph,mirantis,,,12.2.8-1~u16.04+mcp142,12.2.8-1~u16.04+mcp142,,
+librbd1,Distributed storage,Ceph,mirantis,,,12.2.8-1~u16.04+mcp142,12.2.8-1~u16.04+mcp142,,
+librdmacm1,,,,,,,,,
+libreadline5,,,,,,,,,
+libreadline6,,,,,,,,,
+librgw2,Distributed storage,Ceph,mirantis,,,12.2.8-1~u16.04+mcp142,12.2.8-1~u16.04+mcp142,,
+libroken18-heimdal,,,,,,,,,
+librtmp1,,,,,,,,,
+libruby2.3,,,,,,,,,
+libsasl2-2,,,,,,,,,
+libsasl2-modules,,,,,,,,,
+libsasl2-modules-db,,,,,,,,,
+libsdl1.2debian,,,,,,,,,
+libseccomp2,,,,,,,,,
+libselinux1,,,,,,,,,
+libsemanage-common,,,,,,,,,
+libsemanage1,,,,,,,,,
+libsensors4,,,,,,,,,
+libsepol1,,,,,,,,,
+libsgutils2-2,,,,,,,,,
+libsigsegv2,,,,,,,,,
+libslang2,,,,,,,,,
+libsmartcols1,,,,,,,,,
+libsnappy1v5,,,,,,,,,
+libsndfile1,,,,,,,,,
+libsnmp-base,,,,,,,,,
+libsnmp30,,,,,,,,,
+libsodium18,,,,,,,,,
+libspice-server1,,,,,,,,,
+libsqlite3-0,,,,,,,,,
+libss2,,,,,,,,,
+libssh2-1,,,,,,,,,
+libssl1.0.0,,,,,,,,,
+libstdc++6,,,,,,,,,
+libsubunit-perl,,,,,,,,,
+libsysfs2,,,,,,,,,
+libsystemd0,,,,,,,,,
+libtasn1-6,,,,,,,,,
+libtcl8.6,,,,,,,,,
+libtcmalloc-minimal4,,,,,,,,,
+libtext-charwidth-perl,,,,,,,,,
+libtext-iconv-perl,,,,,,,,,
+libtext-wrapi18n-perl,,,,,,,,,
+libthai-data,,,,,,,,,
+libthai0,,,,,,,,,
+libtiff5,,,,,,,,,
+libtinfo5,,,,,,,,,
+libudev1,,,,,,,,,
+libunwind8,,,,,,,,,
+liburcu4,,,,,,,,,
+libusb-0.1-4,,,,,,,,,
+libusb-1.0-0,,,,,,,,,
+libusbredirparser1,,,,,,,,,
+libustr-1.0-1,,,,,,,,,
+libutempter0,,,,,,,,,
+libuuid1,,,,,,,,,
+libv8-3.14.5,,,,,,,,,
+libvirt-bin,Hypervisors,libvirt,mirantis,,,4.0.0-1.7~u16.04+mcp3,4.0.0-1.8.5~u16.04+mcp1,,
+libvirt-clients,Hypervisors,libvirt,mirantis,,,4.0.0-1.7~u16.04+mcp3,4.0.0-1.8.5~u16.04+mcp1,,
+libvirt-daemon,Hypervisors,libvirt,mirantis,,,4.0.0-1.7~u16.04+mcp3,4.0.0-1.8.5~u16.04+mcp1,,
+libvirt-daemon-system,Hypervisors,libvirt,mirantis,,,4.0.0-1.7~u16.04+mcp3,4.0.0-1.8.5~u16.04+mcp1,,
+libvirt-dev,Hypervisors,libvirt,mirantis,,,4.0.0-1.7~u16.04+mcp3,4.0.0-1.8.5~u16.04+mcp1,,
+libvirt-exporter,Hypervisors,libvirt,,,,,,,
+libvirt0,Hypervisors,libvirt,mirantis,,,4.0.0-1.7~u16.04+mcp3,4.0.0-1.8.5~u16.04+mcp1,,
+libvorbis0a,,,,,,,,,
+libvorbisenc2,,,,,,,,,
+libvpx3,,,,,,,,,
+libwind0-heimdal,,,,,,,,,
+libwrap0,,,,,,,,,
+libx11-6,,,,,,,,,
+libx11-data,,,,,,,,,
+libx11-xcb1,,,,,,,,,
+libxau6,,,,,,,,,
+libxcb-dri2-0,,,,,,,,,
+libxcb-dri3-0,,,,,,,,,
+libxcb-glx0,,,,,,,,,
+libxcb-present0,,,,,,,,,
+libxcb-render0,,,,,,,,,
+libxcb-shm0,,,,,,,,,
+libxcb-sync1,,,,,,,,,
+libxcb1,,,,,,,,,
+libxcomposite1,,,,,,,,,
+libxcursor1,,,,,,,,,
+libxdamage1,,,,,,,,,
+libxdmcp6,,,,,,,,,
+libxen-4.6,,,,,,,,,
+libxen-dev,,,,,,,,,
+libxenstore3.0,,,,,,,,,
+libxext6,,,,,,,,,
+libxfixes3,,,,,,,,,
+libxi6,,,,,,,,,
+libxinerama1,,,,,,,,,
+libxml2,,,,,,,,,
+libxmlsec1,,,,,,,,,
+libxmlsec1-openssl,,,,,,,,,
+libxmuu1,,,,,,,,,
+libxpm4,,,,,,,,,
+libxrandr2,,,,,,,,,
+libxrender1,,,,,,,,,
+libxshmfence1,,,,,,,,,
+libxslt1.1,,,,,,,,,
+libxtables11,,,,,,,,,
+libxtst6,,,,,,,,,
+libxxf86vm1,,,,,,,,,
+libyajl2,,,,,,,,,
+libyaml-0-2,,,,,,,,,
+libyaml-cpp0.5v5,,,,,,,,,
+libzmq5,,,,,,,,,
+linux-base,System,Base OS,,,,,,,
+linux-firmware,System,Base OS,,,,,,,
+linux-generic-hwe-16.04,System,Base OS,mirror,,,4.15.0.36.59,4.15.0.43.64,,
+linux-headers-4.15.0-36,System,Base OS,,,,,,,
+linux-headers-4.15.0-36-generic,System,Base OS,,,,,,,
+linux-headers-4.15.0-43,System,Base OS,,,,,,,
+linux-headers-4.15.0-43-generic,System,Base OS,,,,,,,
+linux-headers-4.15.0-45,System,Base OS,,,,,,,
+linux-headers-4.15.0-45-generic,System,Base OS,,,,,,,
+linux-headers-4.4.0-137,System,Base OS,,,,,,,
+linux-headers-4.4.0-137-generic,System,Base OS,,,,,,,
+linux-headers-generic,System,Base OS,,,,,,,
+linux-headers-generic-hwe-16.04,System,Base OS,mirror,,,4.15.0.36.59,4.15.0.43.64,,
+linux-headers-virtual-hwe-16.04,System,Base OS,mirror,,,4.15.0.36.59,4.15.0.43.64,,
+linux-image-4.15.0-36-generic,System,Base OS,,,,,,,
+linux-image-4.15.0-43-generic,System,Base OS,,,,,,,
+linux-image-4.15.0-45-generic,System,Base OS,,,,,,,
+linux-image-4.4.0-130-generic,System,Base OS,,,,,,,
+linux-image-4.4.0-137-generic,System,Base OS,,,,,,,
+linux-image-extra-4.4.0-130-generic,System,Base OS,,,,,,,
+linux-image-extra-4.4.0-137-generic,System,Base OS,,,,,,,
+linux-image-extra-virtual,System,Base OS,,,,,,,
+linux-image-extra-virtual-hwe-16.04,System,Base OS,mirror,,,4.15.0.36.59,4.15.0.43.64,,
+linux-image-extra-virtual-lts-xenial,System,Base OS,,,,,,,
+linux-image-generic,System,Base OS,,,,,,,
+linux-image-generic-hwe-16.04,System,Base OS,mirror,,,4.15.0.36.59,4.15.0.43.64,,
+linux-image-virtual,System,Base OS,,,,,,,
+linux-image-virtual-hwe-16.04,System,Base OS,mirror,,,4.15.0.36.59,4.15.0.43.64,,
+linux-image-virtual-lts-xenial,System,Base OS,,,,,,,
+linux-libc-dev,System,Base OS,,,,,,,
+linux-modules-4.15.0-36-generic,System,Base OS,,,,,,,
+linux-modules-4.15.0-43-generic,System,Base OS,,,,,,,
+linux-modules-4.15.0-45-generic,System,Base OS,,,,,,,
+linux-modules-extra-4.15.0-36-generic,System,Base OS,,,,,,,
+linux-modules-extra-4.15.0-43-generic,System,Base OS,,,,,,,
+linux-modules-extra-4.15.0-45-generic,System,Base OS,,,,,,,
+linux-signed-generic,System,Base OS,,,,,,,
+linux-signed-generic-hwe-16.04,System,Base OS,mirror,,,4.15.0.36.59,4.15.0.43.64,,
+linux-signed-image-4.4.0-137-generic,System,Base OS,,,,,,,
+linux-signed-image-generic,System,Base OS,,,,,,,
+locales,,,,,,,,,
+login,,,,,,,,,
+logrotate,,,,,,,,,
+lsb-base,,,,,,,,,
+lsb-release,,,,,,,,,
+lshw,,,,,,,,,
+lsof,,,,,,,,,
+lsscsi,,,,,,,,,
+ltrace,,,,,,,,,
+lvm2,,,,,,,,,
+lxc-common,,,,,,,,,
+lxcfs,,,,,,,,,
+lxd,,,,,,,,,
+lxd-client,,,,,,,,,
+lzop,,,,,,,,,
+maas,DriveTrain,MAAS,mirror,,,2.3.5,2.3.5,,
+maas-cli,DriveTrain,MAAS,mirror,,,2.3.5,2.3.5,,
+maas-common,DriveTrain,MAAS,mirror,,,2.3.5,2.3.5,,
+maas-dhcp,DriveTrain,MAAS,mirror,,,2.3.5,2.3.5,,
+maas-dns,DriveTrain,MAAS,mirror,,,2.3.5,2.3.5,,
+maas-proxy,DriveTrain,MAAS,mirror,,,2.3.5,2.3.5,,
+maas-rack-controller,DriveTrain,MAAS,mirror,,,2.3.5,2.3.5,,
+maas-region-api,DriveTrain,MAAS,mirror,,,2.3.5,2.3.5,,
+maas-region-controller,DriveTrain,MAAS,mirror,,,2.3.5,2.3.5,,
+make,,,,,,,,,
+makedev,,,,,,,,,
+man-db,,,,,,,,,
+manpages,,,,,,,,,
+mawk,,,,,,,,,
+mc,,,,,,,,,
+mc-data,,,,,,,,,
+mcelog,,,,,,,,,
+mdadm,,,,,,,,,
+memcached,,,,,,,,,
+memtest86+,,,,,,,,,
+mime-support,,,,,,,,,
+minicom,,,,,,,,,
+mlocate,,,,,,,,,
+mongodb,StackLight LMA,MongoDB,mirror,,,2.6.10,2.6.10,,
+mongodb-clients,StackLight LMA,MongoDB,mirror,,,2.6.10,2.6.10,,
+mongodb-server,StackLight LMA,MongoDB,mirror,,,2.6.10,2.6.10,,
+mount,,,,,,,,,
+mtools,,,,,,,,,
+mtr-tiny,,,,,,,,,
+multiarch-support,,,,,,,,,
+mysql-client,System,MySQL,mirror,,,5.6.35,5.6.35-0.1~u16.04+mcp2 [5],,
+mysql-common,System,MySQL,,,,,,,
+mysql-wsrep-5.6,System,MySQL,mirror,,,5.6.35,5.6.35-0.1~u16.04+mcp2 [5],,
+mysql-wsrep-client-5.6,System,MySQL,mirror,,,5.6.35,5.6.35-0.1~u16.04+mcp2 [5],,
+mysql-wsrep-common-5.6,System,MySQL,mirror,,,5.6.35,5.6.35-0.1~u16.04+mcp2 [5],,
+mysql-wsrep-libmysqlclient18,System,MySQL,mirror,,,5.6.35,5.6.35-0.1~u16.04+mcp2 [5],,
+mysql-wsrep-server-5.6,System,MySQL,mirror,,,5.6.35,5.6.35-0.1~u16.04+mcp2 [5],,
+nano,,,,,,,,,
+ncurses-base,,,,,,,,,
+ncurses-bin,,,,,,,,,
+ncurses-term,,,,,,,,,
+net-tools,,,,,,,,,
+netbase,,,,,,,,,
+netcat-openbsd,,,,,,,,,
+netfilter-persistent,,,,,,,,,
+neutron-common,OpenStack Networking,Neutron,mirantis,Queens,,12.0.5-5~u16.04+mcp62,2:12.0.5-5~u16.04+mcp93 [5],,
+neutron-dhcp-agent,OpenStack Networking,Neutron,mirantis,Queens,,12.0.5-5~u16.04+mcp62,2:12.0.5-5~u16.04+mcp93 [5],,
+neutron-l3-agent,OpenStack Networking,Neutron,mirantis,Queens,,12.0.5-5~u16.04+mcp62,2:12.0.5-5~u16.04+mcp93 [5],,
+neutron-metadata-agent,OpenStack Networking,Neutron,mirantis,Queens,,12.0.5-5~u16.04+mcp62,2:12.0.5-5~u16.04+mcp93 [5],,
+neutron-openvswitch-agent,OpenStack Networking,Neutron,mirantis,Queens,,12.0.5-5~u16.04+mcp62,2:12.0.5-5~u16.04+mcp93 [5],,
+neutron-plugin-ml2,OpenStack Networking,Neutron,mirantis,Queens,,12.0.5-5~u16.04+mcp62,2:12.0.5-5~u16.04+mcp93 [5],,
+neutron-server,OpenStack Networking,Neutron,mirantis,Queens,,12.0.5-5~u16.04+mcp62,2:12.0.5-5~u16.04+mcp93 [5],,
+nginx,System,NGINX,mirror,,,1.10.3,1.10.3,,
+nginx-common,System,NGINX,mirror,,,1.10.3,1.10.3,,
+nginx-core,System,NGINX,mirror,,,1.10.3,1.10.3,,
+nova-api,OpenStack,Nova,mirantis,Queens,,17.0.7-6~u16.01+mcp90,2:17.0.9-6~u16.01+mcp93 [5],,
+nova-common,OpenStack,Nova,mirantis,Queens,,17.0.7-6~u16.01+mcp90,2:17.0.9-6~u16.01+mcp93 [5],,
+nova-compute,OpenStack,Nova,mirantis,Queens,,17.0.7-6~u16.01+mcp90,2:17.0.9-6~u16.01+mcp93 [5],,
+nova-compute-kvm,OpenStack,Nova,mirantis,Queens,,17.0.7-6~u16.01+mcp90,2:17.0.9-6~u16.01+mcp93 [5],,
+nova-conductor,OpenStack,Nova,mirantis,Queens,,17.0.7-6~u16.01+mcp90,2:17.0.9-6~u16.01+mcp93 [5],,
+nova-consoleauth,OpenStack,Nova,mirantis,Queens,,17.0.7-6~u16.01+mcp90,2:17.0.9-6~u16.01+mcp93 [5],,
+nova-consoleproxy,OpenStack,Nova,mirantis,Queens,,17.0.7-6~u16.01+mcp90,2:17.0.9-6~u16.01+mcp93 [5],,
+nova-doc,OpenStack,Nova,mirantis,Queens,,17.0.7-6~u16.01+mcp90,2:17.0.9-6~u16.01+mcp93 [5],,
+nova-placement-api,OpenStack,Nova,mirantis,Queens,,17.0.7-6~u16.01+mcp90,2:17.0.9-6~u16.01+mcp93 [5],,
+nova-scheduler,OpenStack,Nova,mirantis,Queens,,17.0.7-6~u16.01+mcp90,2:17.0.9-6~u16.01+mcp93 [5],,
+novnc,,,,,,,,,
+ntfs-3g,,,,,,,,,
+ntp,,,,,,,,,
+nvme-cli,,,,,,,,,
+octavia-api,OpenStack Networking,Octavia,mirantis,Queens,,2.0.2-6~u16.04+mcp62,2.0.2-6~u16.04+mcp69 [5],,
+octavia-common,OpenStack Networking,Octavia,mirantis,Queens,,2.0.2-6~u16.04+mcp62,2.0.2-6~u16.04+mcp69 [5],,
+octavia-health-manager,OpenStack Networking,Octavia,mirantis,Queens,,2.0.2-6~u16.04+mcp62,2.0.2-6~u16.04+mcp69 [5],,
+octavia-housekeeping,OpenStack Networking,Octavia,mirantis,Queens,,2.0.2-6~u16.04+mcp62,2.0.2-6~u16.04+mcp69 [5],,
+octavia-worker,OpenStack Networking,Octavia,mirantis,Queens,,2.0.2-6~u16.04+mcp62,2.0.2-6~u16.04+mcp69 [5],,
+open-iscsi,,,,,,,,,
+open-vm-tools,,,,,,,,,
+openipmi,,,,,,,,,
+openjdk-8-jdk-headless,System,Java,,,,,,,
+openjdk-8-jre,System,Java,,,,,,,
+openjdk-8-jre-headless,System,Java,,,,,,,
+openssh-client,System,SSH,,,,,,,
+openssh-server,System,SSH,,,,,,,
+openssh-sftp-server,System,SSH,,,,,,,
+openssl,System,SSL,,,,,,,
+openstack-dashboard,OpenStack,Horizon,mirantis,Queens,,13.0.1-9~u16.04+mcp,3:13.0.1-10~u16.04+mcp70 [5],,
+openvswitch-common,System,Open vSwitch,mirantis,,,,,,
+openvswitch-switch,System,Open vSwitch,mirantis,,,,,,
+os-brick-common,,,,,,,,,
+os-prober,,,,,,,,,
+overlayroot,,,,,,,,,
+p7zip,,,,,,,,,
+parted,,,,,,,,,
+passwd,,,,,,,,,
+pastebinit,,,,,,,,,
+patch,,,,,,,,,
+pciutils,,,,,,,,,
+percona-xtrabackup,,,,,,,,,
+perl,,,,,,,,,
+perl-base,,,,,,,,,
+perl-modules-5.22,,,,,,,,,
+pkg-config,,,,,,,,,
+plotnetcfg,,,,,,,,,
+plymouth,,,,,,,,,
+plymouth-theme-ubuntu-text,,,,,,,,,
+pm-utils,,,,,,,,,
+policykit-1,,,,,,,,,
+pollinate,,,,,,,,,
+popularity-contest,,,,,,,,,
+postfix,,,,,,,,,
+postgresql,System,PostgreSQL,,,,,,,
+postgresql-9.5,System,PostgreSQL,,,,,,,
+postgresql-client,System,PostgreSQL,,,,,,,
+postgresql-client-9.5,System,PostgreSQL,,,,,,,
+postgresql-client-common,System,PostgreSQL,,,,,,,
+postgresql-common,System,PostgreSQL,,,,,,,
+postgresql-contrib-9.5,System,PostgreSQL,,,,,,,
+postgresql-doc-9.5,System,PostgreSQL,,,,,,,
+powermgmt-base,,,,,,,,,
+procps,,,,,,,,,
+prometheus-bin,StackLight LMA,Prometheus,mirror,,,2.2.1,2.5.0,,
+prometheus-relay,,,,,,,,,
+psmisc,,,,,,,,,
+pxelinux,,,,,,,,,
+pycadf-common,,,,,,,,,
+python,,,,,,,,,
+python-alabaster,,,,,,,,,
+python-alembic,,,,,,,,,
+python-amqp,,,,,,,,,
+python-anyjson,,,,,,,,,
+python-aodhclient,,,,,,,,,
+python-appdirs,,,,,,,,,
+python-apt,,,,,,,,,
+python-apt-common,,,,,,,,,
+python-asn1crypto,,,,,,,,,
+python-automaton,,,,,,,,,
+python-babel,,,,,,,,,
+python-babel-localedata,,,,,,,,,
+python-backports-abc,,,,,,,,,
+python-backports.ssl-match-hostname,,,,,,,,,
+python-barbicanclient,,,,,,,,,
+python-bcrypt,,,,,,,,,
+python-blinker,,,,,,,,,
+python-boto,,,,,,,,,
+python-bs4,,,,,,,,,
+python-bson,,,,,,,,,
+python-cachetools,,,,,,,,,
+python-castellan,,,,,,,,,
+python-ceilometerclient,,,,,,,,,
+python-cephfs,Distributed storage,Ceph,mirantis,,,12.2.8-1~u16.04+mcp142,12.2.8-1~u16.04+mcp142,,
+python-certifi,,,,,,,,,
+python-cffi,,,,,,,,,
+python-cffi-backend,,,,,,,,,
+python-chardet,,,,,,,,,
+python-cherrypy3,,,,,,,,,
+python-cinder,,,,,,,,,
+python-cinderclient,,,,,,,,,
+python-cliff,,,,,,,,,
+python-cmd2,,,,,,,,,
+python-concurrent.futures,,,,,,,,,
+python-contextlib2,,,,,,,,,
+python-cotyledon,,,,,,,,,
+python-croniter,,,,,,,,,
+python-crypto,,,,,,,,,
+python-cryptography,,,,,,,,,
+python-csscompressor,,,,,,,,,
+python-cursive,,,,,,,,,
+python-dateutil,,,,,,,,,
+python-dbus,,,,,,,,,
+python-debtcollector,,,,,,,,,
+python-decorator,,,,,,,,,
+python-defusedxml,,,,,,,,,
+python-deprecation,,,,,,,,,
+python-designateclient,,,,,,,,,
+python-dib-utils,,,,,,,,,
+python-diskimage-builder,,,,,,,,,
+python-django,,,,,,,,,
+python-django-appconf,,,,,,,,,
+python-django-babel,,,,,,,,,
+python-django-common,,,,,,,,,
+python-django-compressor,,,,,,,,,
+python-django-horizon,OpenStack,Horizon,mirantis,Queens,,13.0.1-9~u16.04+mcp,3:13.0.1-10~u16.04+mcp70 [5],,
+python-django-pyscss,,,,,,,,,
+python-dnspython,,,,,,,,,
+python-docker,,,,,,,,,
+python-docutils,,,,,,,,,
+python-dogpile.cache,,,,,,,,,
+python-elasticsearch,,,,,,,,,
+python-enum34,,,,,,,,,
+python-eventlet,,,,,,,,,
+python-extras,,,,,,,,,
+python-fasteners,,,,,,,,,
+python-fixtures,,,,,,,,,
+python-flask,,,,,,,,,
+python-fluent-logger,,,,,,,,,
+python-formencode,,,,,,,,,
+python-funcsigs,,,,,,,,,
+python-functools32,,,,,,,,,
+python-futurist,,,,,,,,,
+python-gerritlib,,,,,,,,,
+python-github,,,,,,,,,
+python-glance,OpenStack,Glance,mirantis,Queens,,16.0.1-2~u16.04+mcp21,2:16.0.1-2~u16.04+mcp23,,
+python-glance-store,OpenStack,Glance,,,,,,,
+python-glanceclient,OpenStack,Glance,,,,,,,
+python-gnocchiclient,,,,,,,,,
+python-googleapi,,,,,,,,,
+python-greenlet,,,,,,,,,
+python-guestfs,,,,,,,,,
+python-gunicorn,,,,,,,,,
+python-heat,OpenStack,Heat,mirantis,Queens,,10.0.2-1.0~u16.04+mcp37,1:10.0.2-1.0~u16.04+mcp54 [5],,
+python-heat-dashboard,,,,,,,,,
+python-heatclient,,,,,,,,,
+python-httplib2,,,,,,,,,
+python-idna,,,,,,,,,
+python-imagesize,,,,,,,,,
+python-ipaddr,,,,,,,,,
+python-ipaddress,,,,,,,,,
+python-iso8601,,,,,,,,,
+python-itsdangerous,,,,,,,,,
+python-jenkins,,,,,,,,,
+python-jinja2,,,,,,,,,
+python-jmespath,,,,,,,,,
+python-json-pointer,,,,,,,,,
+python-jsonpatch,,,,,,,,,
+python-jsonschema,,,,,,,,,
+python-jwt,,,,,,,,,
+python-kazoo,,,,,,,,,
+python-keyring,,,,,,,,,
+python-keystone,OpenStack,Keystone,mirantis,Queens,,13.0.1-3~u16.04+mcp18,2:13.0.2-3~u16.04+mcp15,,
+python-keystoneauth1,,,,,,,,,
+python-keystoneclient,,,,,,,,,
+python-keystonemiddleware,,,,,,,,,
+python-kombu,,,,,,,,,
+python-ldap,,,,,,,,,
+python-ldappool,,,,,,,,,
+python-lesscpy,,,,,,,,,
+python-libvirt,,,,,,,,,
+python-linecache2,,,,,,,,,
+python-logutils,,,,,,,,,
+python-lxml,,,,,,,,,
+python-m2crypto,,,,,,,,,
+python-magnumclient,,,,,,,,,
+python-mako,,,,,,,,,
+python-manilaclient,,,,,,,,,
+python-markupsafe,,,,,,,,,
+python-memcache,,,,,,,,,
+python-microversion-parse,,,,,,,,,
+python-migrate,,,,,,,,,
+python-mimeparse,,,,,,,,,
+python-minimal,,,,,,,,,
+python-mistralclient,,,,,,,,,
+python-mock,,,,,,,,,
+python-monascaclient,,,,,,,,,
+python-monotonic,,,,,,,,,
+python-msgpack,,,,,,,,,
+python-multi-key-dict,,,,,,,,,
+python-munch,,,,,,,,,
+python-mysqldb,,,,,,,,,
+python-ndg-httpsclient,,,,,,,,,
+python-netaddr,,,,,,,,,
+python-netifaces,,,,,,,,,
+python-networkx,,,,,,,,,
+python-neutron,OpenStack Networking,Neutron,mirantis,Queens,,12.0.5-5~u16.04+mcp62,2:12.0.5-5~u16.04+mcp93 [5],,
+python-neutron-fwaas,,,,,,,,,
+python-neutron-lbaas,,,,,,,,,
+python-neutron-lib,,,,,,,,,
+python-neutronclient,,,,,,,,,
+python-nova,OpenStack,Nova,mirantis,Queens,,17.0.7-6~u16.01+mcp90,2:17.0.9-6~u16.01+mcp93 [5],,
+python-novaclient,,,,,,,,,
+python-novnc,,,,,,,,,
+python-numpy,,,,,,,,,
+python-oauth,,,,,,,,,
+python-oauth2client,,,,,,,,,
+python-oauthlib,,,,,,,,,
+python-octavia,OpenStack Networking,Octavia,mirantis,Queens,,2.0.2-6~u16.04+mcp62,2.0.2-6~u16.04+mcp69 [5],,
+python-octavia-dashboard,,,,,,,,,
+python-octaviaclient,,,,,,,,,
+python-openssl,,,,,,,,,
+python-openstackclient,OpenStack,Other,,,,,,,
+python-openstacksdk,OpenStack,Other,,,,,,,
+python-openvswitch,System,Open vSwitch,mirantis,,,2.8.0-4~u16.04+mcp1,2.8.0-4~u16.04+mcp1,,
+python-os-brick,,,,,,,,,
+python-os-client-config,,,,,,,,,
+python-os-service-types,,,,,,,,,
+python-os-traits,,,,,,,,,
+python-os-vif,,,,,,,,,
+python-os-win,,,,,,,,,
+python-os-xenapi,,,,,,,,,
+python-osc-lib,,,,,,,,,
+python-oslo.cache,,,,,,,,,
+python-oslo.concurrency,,,,,,,,,
+python-oslo.config,,,,,,,,,
+python-oslo.context,,,,,,,,,
+python-oslo.db,,,,,,,,,
+python-oslo.i18n,,,,,,,,,
+python-oslo.log,,,,,,,,,
+python-oslo.messaging,,,,,,,,,
+python-oslo.middleware,,,,,,,,,
+python-oslo.policy,,,,,,,,,
+python-oslo.privsep,,,,,,,,,
+python-oslo.reports,,,,,,,,,
+python-oslo.rootwrap,,,,,,,,,
+python-oslo.serialization,,,,,,,,,
+python-oslo.service,,,,,,,,,
+python-oslo.utils,,,,,,,,,
+python-oslo.versionedobjects,,,,,,,,,
+python-oslo.vmware,,,,,,,,,
+python-osprofiler,,,,,,,,,
+python-ovsdbapp,,,,,,,,,
+python-paramiko,,,,,,,,,
+python-passlib,,,,,,,,,
+python-paste,,,,,,,,,
+python-pastedeploy,,,,,,,,,
+python-pastedeploy-tpl,,,,,,,,,
+python-pathlib,,,,,,,,,
+python-pbr,,,,,,,,,
+python-pecan,,,,,,,,,
+python-pika,,,,,,,,,
+python-pika-pool,,,,,,,,,
+python-pint,,,,,,,,,
+python-pip,,,,,,,,,
+python-pip-whl,,,,,,,,,
+python-pkg-resources,,,,,,,,,
+python-pkginfo,,,,,,,,,
+python-ply,,,,,,,,,
+python-positional,,,,,,,,,
+python-posix-ipc,,,,,,,,,
+python-prettytable,,,,,,,,,
+python-psutil,,,,,,,,,
+python-psycopg2,,,,,,,,,
+python-pyasn1,,,,,,,,,
+python-pyasn1-modules,,,,,,,,,
+python-pycadf,,,,,,,,,
+python-pycparser,,,,,,,,,
+python-pycurl,,,,,,,,,
+python-pygerrit2,,,,,,,,,
+python-pygments,,,,,,,,,
+python-pyinotify,,,,,,,,,
+python-pyldap,,,,,,,,,
+python-pymemcache,,,,,,,,,
+python-pymongo,,,,,,,,,
+python-pymysql,,,,,,,,,
+python-pyparsing,,,,,,,,,
+python-pypowervm,,,,,,,,,
+python-pyroute2,,,,,,,,,
+python-pyrss2gen,,,,,,,,,
+python-pysaml2,,,,,,,,,
+python-pyscss,,,,,,,,,
+python-rados,Distributed storage,Ceph,mirantis,,,12.2.8-1~u16.04+mcp142,12.2.8-1~u16.04+mcp142,,
+python-rbd,Distributed storage,Ceph,mirantis,,,12.2.8-1~u16.04+mcp142,12.2.8-1~u16.04+mcp142,,
+python-rcssmin,,,,,,,,,
+python-reclass,DriveTrain,Reclass,,,,1.5.1-1tcp4,1.5.6-1.0~u16.04+mcp0,,
+python-redis,,,,,,,,,
+python-repoze.lru,,,,,,,,,
+python-requests,,,,,,,,,
+python-requestsexceptions,,,,,,,,,
+python-retrying,,,,,,,,,
+python-rfc3986,,,,,,,,,
+python-rgw,Distributed storage,Ceph,mirantis,,,12.2.8-1~u16.04+mcp142,12.2.8-1~u16.04+mcp142,,
+python-rjsmin,,,,,,,,,
+python-roman,,,,,,,,,
+python-routes,,,,,,,,,
+python-rsa,,,,,,,,,
+python-rtslib-fb,,,,,,,,,
+python-ryu,,,,,,,,,
+python-saharaclient,,,,,,,,,
+python-scrypt,,,,,,,,,
+python-semantic-version,,,,,,,,,
+python-senlinclient,,,,,,,,,
+python-setproctitle,,,,,,,,,
+python-setuptools,,,,,,,,,
+python-simplegeneric,,,,,,,,,
+python-simplejson,,,,,,,,,
+python-singledispatch,,,,,,,,,
+python-six,,,,,,,,,
+python-sphinx,,,,,,,,,
+python-sqlalchemy,,,,,,,,,
+python-sqlparse,,,,,,,,,
+python-statsd,,,,,,,,,
+python-stevedore,,,,,,,,,
+python-subunit,,,,,,,,,
+python-suds,,,,,,,,,
+python-swiftclient,,,,,,,,,
+python-systemd,,,,,,,,,
+python-taskflow,,,,,,,,,
+python-tempita,,,,,,,,,
+python-tenacity,,,,,,,,,
+python-testtools,,,,,,,,,
+python-tinyrpc,,,,,,,,,
+python-tooz,,,,,,,,,
+python-tornado,,,,,,,,,
+python-traceback2,,,,,,,,,
+python-troveclient,,,,,,,,,
+python-typing,,,,,,,,,
+python-tz,,,,,,,,,
+python-ujson,,,,,,,,,
+python-unicodecsv,,,,,,,,,
+python-unittest2,,,,,,,,,
+python-uritemplate,,,,,,,,,
+python-urllib3,,,,,,,,,
+python-vine,,,,,,,,,
+python-voluptuous,,,,,,,,,
+python-waitress,,,,,,,,,
+python-warlock,,,,,,,,,
+python-weakrefmethod,,,,,,,,,
+python-webob,,,,,,,,,
+python-websocket,,,,,,,,,
+python-websockify,,,,,,,,,
+python-webtest,,,,,,,,,
+python-werkzeug,,,,,,,,,
+python-wrapt,,,,,,,,,
+python-wsme,,,,,,,,,
+python-xstatic,,,,,,,,,
+python-xstatic-angular,,,,,,,,,
+python-xstatic-angular-bootstrap,,,,,,,,,
+python-xstatic-angular-fileupload,,,,,,,,,
+python-xstatic-angular-gettext,,,,,,,,,
+python-xstatic-angular-lrdragndrop,,,,,,,,,
+python-xstatic-angular-schema-form,,,,,,,,,
+python-xstatic-bootstrap-datepicker,,,,,,,,,
+python-xstatic-bootstrap-scss,,,,,,,,,
+python-xstatic-bootswatch,,,,,,,,,
+python-xstatic-d3,,,,,,,,,
+python-xstatic-font-awesome,,,,,,,,,
+python-xstatic-hogan,,,,,,,,,
+python-xstatic-jasmine,,,,,,,,,
+python-xstatic-jquery,,,,,,,,,
+python-xstatic-jquery-migrate,,,,,,,,,
+python-xstatic-jquery-ui,,,,,,,,,
+python-xstatic-jquery.quicksearch,,,,,,,,,
+python-xstatic-jquery.tablesorter,,,,,,,,,
+python-xstatic-jsencrypt,,,,,,,,,
+python-xstatic-magic-search,,,,,,,,,
+python-xstatic-mdi,,,,,,,,,
+python-xstatic-objectpath,,,,,,,,,
+python-xstatic-rickshaw,,,,,,,,,
+python-xstatic-roboto-fontface,,,,,,,,,
+python-xstatic-smart-table,,,,,,,,,
+python-xstatic-spin,,,,,,,,,
+python-xstatic-term.js,,,,,,,,,
+python-xstatic-tv4,,,,,,,,,
+python-yaml,,,,,,,,,
+python-yaql,,,,,,,,,
+python-zake,,,,,,,,,
+python-zaqarclient,,,,,,,,,
+python-zmq,,,,,,,,,
+python-zope.interface,,,,,,,,,
+python-zunclient,,,,,,,,,
+python2.7,,,,,,,,,
+python2.7-minimal,,,,,,,,,
+python3,,,,,,,,,
+python3-alabaster,,,,,,,,,
+python3-apport,,,,,,,,,
+python3-apt,,,,,,,,,
+python3-asn1crypto,,,,,,,,,
+python3-attr,,,,,,,,,
+python3-babel,,,,,,,,,
+python3-blinker,,,,,,,,,
+python3-bson,,,,,,,,,
+python3-certifi,,,,,,,,,
+python3-cffi,,,,,,,,,
+python3-cffi-backend,,,,,,,,,
+python3-chardet,,,,,,,,,
+python3-commandnotfound,,,,,,,,,
+python3-configobj,,,,,,,,,
+python3-convoy,,,,,,,,,
+python3-crochet,,,,,,,,,
+python3-crypto,,,,,,,,,
+python3-cryptography,,,,,,,,,
+python3-curtin,,,,,,,,,
+python3-dbus,,,,,,,,,
+python3-debian,,,,,,,,,
+python3-distro-info,,,,,,,,,
+python3-distupgrade,,,,,,,,,
+python3-django,,,,,,,,,
+python3-django-maas,,,,,,,,,
+python3-django-piston3,,,,,,,,,
+python3-djorm-ext-pgarray,,,,,,,,,
+python3-dnspython,,,,,,,,,
+python3-docutils,,,,,,,,,
+python3-ecdsa,,,,,,,,,
+python3-extras,,,,,,,,,
+python3-fixtures,,,,,,,,,
+python3-formencode,,,,,,,,,
+python3-gdbm,,,,,,,,,
+python3-gi,,,,,,,,,
+python3-httplib2,,,,,,,,,
+python3-idna,,,,,,,,,
+python3-imagesize,,,,,,,,,
+python3-iso8601,,,,,,,,,
+python3-jinja2,,,,,,,,,
+python3-json-pointer,,,,,,,,,
+python3-jsonpatch,,,,,,,,,
+python3-jsonschema,,,,,,,,,
+python3-jwt,,,,,,,,,
+python3-linecache2,,,,,,,,,
+python3-lxml,,,,,,,,,
+python3-maas-client,,,,,,,,,
+python3-maas-provisioningserver,,,,,,,,,
+python3-markupsafe,,,,,,,,,
+python3-mimeparse,,,,,,,,,
+python3-minimal,,,,,,,,,
+python3-netaddr,,,,,,,,,
+python3-netifaces,,,,,,,,,
+python3-newt,,,,,,,,,
+python3-oauth,,,,,,,,,
+python3-oauthlib,,,,,,,,,
+python3-openssl,,,,,,,,,
+python3-paramiko,,,,,,,,,
+python3-pbr,,,,,,,,,
+python3-petname,,,,,,,,,
+python3-pexpect,,,,,,,,,
+python3-pkg-resources,,,,,,,,,
+python3-ply,,,,,,,,,
+python3-prettytable,,,,,,,,,
+python3-problem-report,,,,,,,,,
+python3-psycopg2,,,,,,,,,
+python3-ptyprocess,,,,,,,,,
+python3-pyasn1,,,,,,,,,
+python3-pyasn1-modules,,,,,,,,,
+python3-pycparser,,,,,,,,,
+python3-pycurl,,,,,,,,,
+python3-pygments,,,,,,,,,
+python3-pyparsing,,,,,,,,,
+python3-pyvmomi,,,,,,,,,
+python3-requests,,,,,,,,,
+python3-roman,,,,,,,,,
+python3-seamicroclient,,,,,,,,,
+python3-serial,,,,,,,,,
+python3-service-identity,,,,,,,,,
+python3-simplejson,,,,,,,,,
+python3-simplestreams,,,,,,,,,
+python3-six,,,,,,,,,
+python3-software-properties,,,,,,,,,
+python3-sphinx,,,,,,,,,
+python3-sphinx-rtd-theme,,,,,,,,,
+python3-subunit,,,,,,,,,
+python3-systemd,,,,,,,,,
+python3-tempita,,,,,,,,,
+python3-testtools,,,,,,,,,
+python3-traceback2,,,,,,,,,
+python3-twisted,,,,,,,,,
+python3-txtftp,,,,,,,,,
+python3-tz,,,,,,,,,
+python3-unittest2,,,,,,,,,
+python3-update-manager,,,,,,,,,
+python3-urllib3,,,,,,,,,
+python3-virtualenv,,,,,,,,,
+python3-yaml,,,,,,,,,
+python3-zope.interface,,,,,,,,,
+python3.5,,,,,,,,,
+python3.5-minimal,,,,,,,,,
+qemu-block-extra,Hypervisors,qemu,mirantis,,,2.11+dfsg-1.4~u16.04+mcp2,1:2.11+dfsg-1.4~u16.04+mcp2,,
+qemu-kvm,Hypervisors,qemu,mirantis,,,2.11+dfsg-1.4~u16.04+mcp2,1:2.11+dfsg-1.4~u16.04+mcp2,,
+qemu-system-common,Hypervisors,qemu,mirantis,,,2.11+dfsg-1.4~u16.04+mcp2,1:2.11+dfsg-1.4~u16.04+mcp2,,
+qemu-system-x86,Hypervisors,qemu,mirantis,,,2.11+dfsg-1.4~u16.04+mcp2,1:2.11+dfsg-1.4~u16.04+mcp2,,
+qemu-utils,Hypervisors,qemu,mirantis,,,2.11+dfsg-1.4~u16.04+mcp2,1:2.11+dfsg-1.4~u16.04+mcp2,,
+rabbitmq-server,System,RabbitMQ,mirantis,,,3.6.15-3~u16.04+mcp1,3.6.15-3~u16.04+mcp1,,
+radosgw,Distributed storage,Ceph,mirantis,,,12.2.8-1~u16.04+mcp142,12.2.8-1~u16.04+mcp142,,
+radvd,,,,,,,,,
+rake,,,,,,,,,
+readline-common,,,,,,,,,
+reclass,,,,,,,,,
+rename,,,,,,,,,
+resolvconf,,,,,,,,,
+rsync,,,,,,,,,
+rsyslog,,,,,,,,,
+ruby,System,Ruby,,,,,,,
+ruby-did-you-mean,System,Ruby,,,,,,,
+ruby-minitest,System,Ruby,,,,,,,
+ruby-net-telnet,System,Ruby,,,,,,,
+ruby-power-assert,System,Ruby,,,,,,,
+ruby-test-unit,System,Ruby,,,,,,,
+ruby2.3,System,Ruby,,,,,,,
+rubygems-integration,,,,,,,,,
+run-one,,,,,,,,,
+s-nail,,,,,,,,,
+salt-api,DriveTrain,SaltStack,mirror,,2017.7.7,2017.7.7,2017.7.8,,
+salt-common,DriveTrain,SaltStack,mirror,,2017.7.7,2017.7.7,2017.7.8,,
+salt-formula-aodh,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-apache,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-aptcacher,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-aptly,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-artifactory,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-auditd,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-avinetworks,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-backupninja,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-barbican,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-baremetal-simulator,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-billometer,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-bind,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-bird,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-cadf,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-cassandra,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-ccp,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-ceilometer,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-ceph,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-chrony,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-cinder,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-collectd,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-debmirror,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-decapod,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-designate,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-devops-portal,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-docker,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-dogtag,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-dovecot,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-elasticsearch,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-etcd,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-fluentbit,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-fluentd,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-foreman,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-freeipa,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-galera,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-gerrit,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-git,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-gitlab,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-glance,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-glusterfs,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-gnocchi,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-grafana,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-graphite,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-haproxy,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-heat,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-heka,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-helm,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-horizon,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-influxdb,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-iptables,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-ironic,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-isc-dhcp,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-java,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-jenkins,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-kedb,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-keepalived,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-keycloak,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-keystone,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-kibana,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-kubernetes,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-letsencrypt,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-libvirt,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-linux,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-lldp,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-logrotate,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-maas,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-magnum,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-manila,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-memcached,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-midonet,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-mirascan,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-mongodb,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-murano,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-mysql,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-nagios,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-network,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-neutron,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-nfs,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-nginx,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-nodejs,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-nova,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-ntp,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-octavia,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-opencontrail,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-openldap,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-openssh,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-openvpn,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-openvstorage,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-oslo-templates,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-owncloud,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-panko,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-postfix,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-postgresql,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-powerdns,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-pritunl,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-prometheus,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-python,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-rabbitmq,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-reclass,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-redis,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-roundcube,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-rsync,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-rsyslog,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-rundeck,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-runtest,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-sahara,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-salt,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-sensu,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-sentry,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-shibboleth,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-sphinx,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-statsd,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-supervisor,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-swift,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-taiga,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-telegraf,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-tftpd-hpa,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-tinyproxy,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-varnish,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-watchdog,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-xtrabackup,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-formula-zookeeper,DriveTrain,Salt Formulas,mirantis,,,,,,
+salt-master,DriveTrain,SaltStack,mirror,,,2017.7.7,2017.7.8,,
+salt-minion,DriveTrain,SaltStack,mirror,,,2017.7.7,2017.7.8,,
+salt-pepper,DriveTrain,SaltStack,,,,,,,
+sbsigntool,,,,,,,,,
+screen,,,,,,,,,
+scrub,,,,,,,,,
+seabios,,,,,,,,,
+sed,,,,,,,,,
+sensible-utils,,,,,,,,,
+sg3-utils,,,,,,,,,
+sgml-base,,,,,,,,,
+shared-mime-info,,,,,,,,,
+smartmontools,,,,,,,,,
+snapd,,,,,,,,,
+snmp,,,,,,,,,
+socat,,,,,,,,,
+software-properties-common,,,,,,,,,
+sosreport,,,,,,,,,
+spawn-fcgi,,,,,,,,,
+sphinx-common,,,,,,,,,
+sphinx-rtd-theme-common,,,,,,,,,
+spice-html5,,,,,,,,,
+sqlite3,,,,,,,,,
+squashfs-tools,,,,,,,,,
+squid,,,,,,,,,
+squid-common,,,,,,,,,
+squid-langpack,,,,,,,,,
+ssh-import-id,,,,,,,,,
+ssl-cert,,,,,,,,,
+strace,,,,,,,,,
+subunit,,,,,,,,,
+sudo,,,,,,,,,
+supermin,,,,,,,,,
+sysfsutils,,,,,,,,,
+syslinux,,,,,,,,,
+syslinux-common,,,,,,,,,
+sysstat,,,,,,,,,
+systemd,,,,,,,,,
+systemd-sysv,,,,,,,,,
+sysv-rc,,,,,,,,,
+sysvinit-utils,,,,,,,,,
+tar,,,,,,,,,
+tcpd,,,,,,,,,
+tcpdump,System,Networking,,,,,,,
+td-agent,,,,,,,,,
+td-agent-additional-plugins,,,,,,,,,
+telegraf,StackLight LMA,Telegraf,,,,,,,
+tgt,,,,,,,,,
+thermald,,,,,,,,,
+thin-provisioning-tools,,,,,,,,,
+time,,,,,,,,,
+tmux,,,,,,,,,
+traceroute,,,,,,,,,
+tree,,,,,,,,,
+tzdata,,,,,,,,,
+ubuntu-cloudimage-keyring,,,,,,,,,
+ubuntu-core-launcher,,,,,,,,,
+ubuntu-keyring,,,,,,,,,
+ubuntu-minimal,,,,,,,,,
+ubuntu-release-upgrader-core,,,,,,,,,
+ubuntu-server,,,,,,,,,
+ubuntu-standard,,,,,,,,,
+ucf,,,,,,,,,
+udev,,,,,,,,,
+ufw,,,,,,,,,
+uidmap,,,,,,,,,
+unzip,,,,,,,,,
+update-manager-core,,,,,,,,,
+update-motd,,,,,,,,,
+update-notifier-common,,,,,,,,,
+ureadahead,,,,,,,,,
+usbutils,,,,,,,,,
+util-linux,,,,,,,,,
+uuid-runtime,,,,,,,,,
+vim,,,,,,,,,
+vim-common,,,,,,,,,
+vim-nox,,,,,,,,,
+vim-runtime,,,,,,,,,
+vim-tiny,,,,,,,,,
+virt-what,,,,,,,,,
+virtualenv,,,,,,,,,
+vlan,,,,,,,,,
+websockify,,,,,,,,,
+websockify-common,,,,,,,,,
+wget,,,,,,,,,
+whiptail,,,,,,,,,
+wireless-regdb,,,,,,,,,
+x11-common,,,,,,,,,
+xauth,,,,,,,,,
+xdg-user-dirs,,,,,,,,,
+xfsprogs,,,,,,,,,
+xkb-data,,,,,,,,,
+xml-core,,,,,,,,,
+xmlsec1,,,,,,,,,
+xz-utils,,,,,,,,,
+zerofree,,,,,,,,,
+zlib1g,,,,,,,,,
+zlib1g-dev,,,,,,,,,
diff --git a/templates/common_scripts.j2 b/templates/common_scripts.j2
new file mode 100644
index 0000000..2ea3614
--- /dev/null
+++ b/templates/common_scripts.j2
@@ -0,0 +1,56 @@
+<script language="JavaScript">
+ function toggleClassByID(pkg) {
+ var element = document.getElementById(pkg);
+ //var button = document.getElementById(pkg+"_button");
+
+ if( element.className && element.className.indexOf("in") > -1 ) {
+ element.classList.remove("in");
+ //button.innerHTML = "↑"
+ }
+ else {
+ element.classList.add("in");
+ //button.innerHTML = "↓"
+ }
+ }
+ </script>
+ <script language="JavaScript">
+ function init() {
+ // Declare all variables
+ var i, content, items;
+
+ // Get all elements with class="barcontent" and hide them
+ content = document.getElementsByClassName("barcontent");
+ for (i = 1; i < content.length; i++) {
+ content[i].style.display = "none";
+ }
+ content[0].style.display = "block";
+
+ // Get all elements with class="bar-item" and remove the class "active"
+ items = document.getElementsByClassName("bar-item");
+ for (i = 1; i < items.length; i++) {
+ items[i].className = items[i].className.replace(" active", "");
+ }
+ items[0].className += " active";
+
+ }
+ function openBar(evt, barName) {
+ // Declare all variables
+ var i, barcontent, baritems;
+
+ // Get all elements with class="barcontent" and hide them
+ barcontent = document.getElementsByClassName("barcontent");
+ for (i = 0; i < barcontent.length; i++) {
+ barcontent[i].style.display = "none";
+ }
+
+ // Get all elements with class="bar-item" and remove the class "active"
+ baritems = document.getElementsByClassName("bar-item");
+ for (i = 0; i < baritems.length; i++) {
+ baritems[i].className = baritems[i].className.replace(" active", "");
+ }
+
+ // Show the current tab, and add an "active" class to the link that opened the tab
+ document.getElementById(barName).style.display = "block";
+ evt.currentTarget.className += " active";
+ }
+ </script>
diff --git a/templates/common_styles.j2 b/templates/common_styles.j2
new file mode 100644
index 0000000..604564b
--- /dev/null
+++ b/templates/common_styles.j2
@@ -0,0 +1,95 @@
+<style>
+ body {
+ font-family: "Open Sans", Arial, Helvetica, sans-serif;
+ font-size: 90% !important;
+ }
+ h5 {padding-left: 1em; margin: 0.6em}
+ .note {font-style: italic; font-weight: normal; padding-left: 1em; margin: 0.2em; font-size: 0.7em; color: gray;}
+ /* Common */
+ .header {
+ display:block;
+ }
+
+ .label {float: left; font-size: 0.7em; color: Black; line-height: 17px; padding-left: 10px;}
+ .text {float: left; font-size: 0.8em; color: Navy; padding-left: 2px;}
+ .date {float: right;}
+
+ .smallgreytext {float: right; font-size: 0.5em; color: gray;}
+
+ /* Bar */
+ .bar{
+ background: linear-gradient(to bottom, #126666 0%, #284753 77%);
+ width:100%;
+ overflow:hidden;
+ display: inline-block;
+ }
+ .bar .bar-item{
+ padding:8px 16px;
+ float:left;
+ width:auto;
+ border:none;
+ display:block;
+ outline:0;
+ color: White;
+ background-color: transparent;
+ }
+
+ .bar .bar-item:hover {
+ background-color: #328686;
+ }
+
+ .bar .bar-item.active {
+ background-color: #328686;
+ color: white;
+ }
+
+ .collapsable {
+ visibility: collapse;
+ display: none;
+ }
+
+ .collapsable.in {
+ visibility: visible;
+ display: table-row;
+ }
+
+ table {
+ border: 0 hidden;
+ table-layout: fixed;
+ width: 100%;
+ }
+
+ .table_header {
+ background-color: #284753;
+ color: wheat;
+ text-align: center;
+ font-family: "Open Sans", Arial, Helvetica, sans-serif;
+ }
+
+ /* Tooltip container */
+ .tooltip {
+ position: relative;
+ display: inline-block;
+ border-bottom: 1px dotted black;
+ }
+
+ .tooltip .tooltiptext {
+ visibility: hidden;
+ background-color: black;
+ font-family: "Lucida Console", Monaco, monospace;
+ font-size: 0.5em;
+ width: auto;
+ color: #fff;
+ border-radius: 6px;
+ padding: 5px 5px;
+
+ /* Position the tooltip */
+ position: absolute;
+ z-index: 1;
+ }
+
+ .tooltip:hover .tooltiptext {
+ visibility: visible;
+ }
+
+</style>
diff --git a/templates/network_check_tmpl.j2 b/templates/network_check_tmpl.j2
index 553b554..9f0f556 100644
--- a/templates/network_check_tmpl.j2
+++ b/templates/network_check_tmpl.j2
@@ -2,207 +2,120 @@
<html lang="en">
<head>
<meta charset="UTF-8">
- <title>Model Tree Changes</title>
+ <title>Nodes and Networks report</title>
+ {% include 'common_styles.j2' %}
+ {% include 'common_scripts.j2' %}
<style>
- body {
- font-family: Verdana, Geneva, Tahoma, sans-serif;
- font-size: 90% !important;
+ table.cluster_nodes {
+ width: 90%;
+ margin-left: 5%;
+ margin-right: 5%;
}
- .dot_green {
- float: left;
- color: green;
- margin-right: 0.5em;
- margin-top: 0.2em;
- }
- .dot_red {
- float: left;
- color: red;
- margin-right: 0.5em;
- margin-top: 0.2em;
- }
- .dot_empty {
- float: left;
- color: darkgray;
- margin-right: 0.5em;
- margin-top: 0.2em;
- }
- /* Style the tab */
- .tab {
- float: left;
- width: 130px;
- border: 1px solid #fff;
- background-color: #efe;
- }
-
- /* Style the buttons that are used to open the tab content */
- .tab button {
+
+ /* Node rows*/
+ .node {
+ display: inline-block;
+ background-color: white;
+ }
+
+ tr.node > td {
display: block;
- background-color: inherit;
- color: Black;
- border: none;
- outline: none;
- font-family: "Lucida Console", Monaco, monospace;
- text-align: left;
- cursor: pointer;
- transition: 0.3s;
- font-size: 1.3em;
- width: 100%;
- padding: 1px;
- margin: 1px;
- }
-
- button > div.node_name {
float: left;
- font-size: 1.3em;
- }
-
- .smallgreytext {
- float: right;
- font-size: 0.7em;
- color: gray;
- }
-
- /* Change background color of buttons on hover */
- .tab button:hover {
- background-color: #7b7;
- }
-
- /* Create an active/current "tab button" class */
- .tab button.active {
- background-color: #8c8;
- color: white;
- }
-
- /* Style the tab content */
- .tabcontent {
- display: none;
- position: absolute;
- font-size: 1em;
- padding: 0.5em;
- right: -10%;
- top: 0%;
- transform: translateX(-12%);
- width: calc(100% - 170px);
- overflow-x: scroll;
- overflow-wrap: break-word;
- }
-
- table {
- border: 0 hidden;
- width: 100%;
- }
- tr:nth-child(even) {
- background-color: #fff;
- }
- tr:nth-child(odd) {
- background-color: #ddd;
- }
- .Header {
- background-color: #bbb;
- color: Black;
- width: 30%;
- text-align: center;
- }
- .param {
- font-size: 0.8em;
- color: #555;
- padding-left: 50px;
- padding-right: 10px;
- }
- .class_file {
- font-size: 0.8em;
- font-weight: bold;
- min-width: 300px;
- text-align: left;
+ padding: 1px;
+ padding-left: 5px;
+ padding-right: 5px;
color: black;
+ background-color: #A1BbA1;
+ text-align: center;
+ margin: 2px;
}
-
- .pkgName {
- font-size: 1em;
- padding-left: 10px;
- max-width: 800px;
+
+ .meters {
+ display: inline-block;
}
-
- .version {
- font-size: 1em;
- text-align: left;
- max-width: 400px;
- overflow-wrap: break-word;
+
+ td.meters > .meter {
+ display: block;
+ float: left;
}
-
- .differ {
- background-color: #eaa;
- }
- /* Tooltip container */
- .tooltip {
- position: relative;
- display: inline-block;
- border-bottom: 1px dotted black;
- }
-
- .tooltip .tooltiptext {
- visibility: hidden;
- background-color: black;
- font-family: "Lucida Console", Monaco, monospace;
- font-size: 0.5em;
- width: auto;
- color: #fff;
- border-radius: 6px;
- padding: 5px 5px;
-
- /* Position the tooltip */
- position: absolute;
- z-index: 1;
- }
-
- .tooltip:hover .tooltiptext {
- visibility: visible;
- }
-
</style>
- <script language="JavaScript">
- function init() {
- // Declare all variables
- var i, tabcontent, tablinks;
-
- // Get all elements with class="tabcontent" and hide them
- tabcontent = document.getElementsByClassName("tabcontent");
- for (i = 1; i < tabcontent.length; i++) {
- tabcontent[i].style.display = "none";
- }
- tabcontent[0].style.display = "block";
-
- // Get all elements with class="tablinks" and remove the class "active"
- tablinks = document.getElementsByClassName("tablinks");
- for (i = 1; i < tablinks.length; i++) {
- tablinks[i].className = tablinks[i].className.replace(" active", "");
- }
- tablinks[0].className += " active";
-
- }
- function openTab(evt, tabName) {
- // Declare all variables
- var i, tabcontent, tablinks;
-
- // Get all elements with class="tabcontent" and hide them
- tabcontent = document.getElementsByClassName("tabcontent");
- for (i = 0; i < tabcontent.length; i++) {
- tabcontent[i].style.display = "none";
- }
-
- // Get all elements with class="tablinks" and remove the class "active"
- tablinks = document.getElementsByClassName("tablinks");
- for (i = 0; i < tablinks.length; i++) {
- tablinks[i].className = tablinks[i].className.replace(" active", "");
- }
-
- // Show the current tab, and add an "active" class to the link that opened the tab
- document.getElementById(tabName).style.display = "block";
- evt.currentTarget.className += " active";
- }
- </script>
</head>
<body onload="init()">
+<div class="header">
+ <div class="label">OpenStack release:</div>
+ <div class="text">{{ openstack_release }}</div>
+ <div class="label">MCP Version:</div>
+ <div class="text">{{ mcp_release }}</div>
+ <div class="label date">generated on: {{ gen_date }}</div>
+</div>
+
+<div class="bar">
+ <button class="bar-item" onclick="openBar(event, 'nodes')">Nodes</button>
+ <button class="bar-item" onclick="openBar(event, 'networks')">Networks</button>
+ <button class="bar-item" onclick="openBar(event, 'services')">Other</button>
+</div>
+
+{% macro nodes_page(nodes, id_label) %}
+<div id="{{ id_label }}" class="barcontent">
+ <h5>{{ caller() }}</h5>
+ <hr>
+ <table class="cluster_nodes">
+ {% for node in nodes.keys() | sort %}
+ {% set _ndat = nodes[node] %}
+ <tr class="node virt">
+ <td class="status">{{ _ndat['status'] }}</td>
+ <td class="name">{{ node }}</td>
+ <td class="role">{{ _ndat['role'] }}</td>
+ <td class="vendor">QEMU</td>
+ <td class="meter cpu">vCPU: 12</td>
+ <td class="meter ram">RAM: 500GB</td>
+ <td class="meter disk">VDA: 150/140/135</td>
+ </tr>
+ {% endfor %}
+ </table>
+ <hr>
+</div>
+{% endmacro %}
+
+{% macro networks_page(networks, id_label) %}
+<div id="{{ id_label }}" class="barcontent">
+ <h5>{{ caller() }}</h5>
+ <hr>
+ <table class="networks">
+ <tr class="subnet">192.168.10.0/24</tr>
+ <tr class="net collapsable">
+ <td class="status">UP</td>
+ <td class="name">cfg01.internal.net</td>
+ <td class="ip">192.168.10.11</td>
+ <td class="param">1500</td>
+ </tr>
+ </table>
+ <hr>
+</div>
+{% endmacro %}
+
+{% macro services_page(services, id_label) %}
+<div id="{{ id_label }}" class="barcontent">
+ <h5>{{ caller() }}</h5>
+ <hr>
+</div>
+{% endmacro %}
+
+<!-- Cluster nodes page -->
+{% call nodes_page(nodes, "nodes") %}
+ Cluster nodes status and simple meterings
+{% endcall %}
+
+<!-- Cluster nodes page -->
+{% call networks_page(networks, "networks") %}
+ Networks in the cluster
+{% endcall %}
+
+<!-- Cluster nodes page -->
+{% call services_page(services, "services") %}
+ Services status in the cluster
+{% endcall %}
+
</body>
</html>
\ No newline at end of file
diff --git a/templates/pkg_versions_csv.j2 b/templates/pkg_versions_csv.j2
new file mode 100644
index 0000000..c754f63
--- /dev/null
+++ b/templates/pkg_versions_csv.j2
@@ -0,0 +1,23 @@
+{% macro package_list(pkg_dict, id_label) %}
+ {% for pkg_name in pkg_dict | get_sorted_keys %}
+ {% set p = pkg_dict[pkg_name] %}
+ {% for status in p['results'].keys() | sort(reverse=true) %}
+ {% for action in p['results'][status].keys() | sort(reverse=true) %}
+ {% for node in p['results'][status][action].keys() | sort %}
+ {% set nd = p['results'][status][action][node] %}
+{{ id_label }},{{ pkg_name }},{{ node }},{{ status | make_status_label }},{{ action | make_action_label }},{{ nd['i'].version }},{{ nd['c'].version }},{{ p['r'].version }}
+ {% endfor %}
+ {% endfor %}
+ {% endfor %}
+ {% endfor %}
+ {{ caller() }}
+{% endmacro %}
+type,package_name,node,status,action,installed,candidate,release
+{% call package_list(critical, "mirantis") %}
+{% endcall %}
+{% call package_list(system, "system") %}
+{%- endcall %}
+{% call package_list(other, "other") %}
+{%- endcall %}
+{% call package_list(unlisted, "unlisted") %}
+{%- endcall %}
diff --git a/templates/pkg_versions_html.j2 b/templates/pkg_versions_html.j2
new file mode 100644
index 0000000..d1b71bb
--- /dev/null
+++ b/templates/pkg_versions_html.j2
@@ -0,0 +1,328 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8">
+ <title>Cloud Package versions check</title>
+ {% include 'common_styles.j2' %}
+ {% include 'common_scripts.j2' %}
+ <style>
+ td.repo {width: 3em; text-align: center; font-size: 0.7em; color: #113b11; font-family: 'Trebuchet MS', 'Lucida Sans Unicode', 'Lucida Grande', 'Lucida Sans', Arial, sans-serif;}
+ td.component, td.app, td.package_name {
+ font-size: 0.75em;
+ text-align: center;
+ color: #113b11;
+ font-family: 'Trebuchet MS', 'Lucida Sans Unicode', 'Lucida Grande', 'Lucida Sans', Arial, sans-serif;
+ }
+
+ td.repo {column-width: 50px;}
+ td.component {column-width: 130px;}
+ td.app {column-width: 80px;}
+ td.package_name {column-width: 200px; padding-left: 10px; text-align: left;}
+ td.node_name {column-width: 210px;}
+ td.installed {column-width: 16%;}
+ td.status_container {column-width: 200px;}
+ td.candidate {column-width: 16%;}
+ td.release {column-width: 13%;}
+
+ .status_container {
+ display: inline-block;
+ }
+
+ .status {
+ display: block;
+ float: left;
+ width: 80px;
+ padding: 1px;
+ padding-left: 5px;
+ padding-right: 5px;
+ color: white;
+ background-color: #113b11;
+ text-align: center;
+ }
+ .action {
+ display: block;
+ float: left;
+ width: 120px;
+ padding: 1px;
+ padding-left: 5px;
+ padding-right: 5px;
+ color: gray;
+ background-color: #d4dad9;
+ text-align: center;
+ }
+
+ .status_container .ok {
+ color: white;
+ background-color: #113b11;
+ }
+ .status_container .error {
+ color: white;
+ background-color: darkred;
+ }
+ .status_container .upgraded {
+ color: azure;
+ background-color: green;
+ }
+ .status_container .downgraded {
+ color: white;
+ background-color: darkolivegreen;
+ }
+
+ .status_container .needs_repo {
+ color: black;
+ background-color: #50aacc;
+ }
+
+ .status_container .needs_up {
+ color: black;
+ background-color: #aaccaa;
+ }
+
+ .status_container .needs_down {
+ color: black;
+ background-color: #ffcc48;
+ }
+
+ .status_container .possible {
+ color: gray;
+ background-color: #d4dad9;
+ }
+
+
+
+ .version {text-align: left; padding: 2px}
+ .v_epoch, .v_upstream, .v_debian, .colon, .dash {
+ color: darkslategray;
+ float: left;
+ display: block;
+ }
+
+ .ok {color: darkslategray;}
+ .error {color: white; background-color: darkred;}
+ .upgraded {color: whitesmoke; background-color: darkslategray;}
+ .downgraded {color: red;}
+
+ .smallgreytext {float: right; font-size: 0.5em; color: gray;}
+
+ /* Table specific */
+ .nodes tr:nth-child(even) {
+ background-color: #fff;
+ }
+ .nodes tr:nth-child(odd) {
+ background-color: #d4dad9;
+
+ }
+ </style>
+</head>
+<body onload="init()">
+
+<div class="header">
+ <div class="label">OpenStack release:</div>
+ <div class="text">{{ openstack_release }}</div>
+ <div class="label">MCP Version:</div>
+ <div class="text">{{ mcp_release }}</div>
+ <div class="label date">generated on: {{ gen_date }}</div>
+</div>
+
+<div class="bar">
+ <button class="bar-item" onclick="openBar(event, 'mirantis')">Mirantis</button>
+ <button class="bar-item" onclick="openBar(event, 'system')">System</button>
+ <button class="bar-item" onclick="openBar(event, 'other')">Other</button>
+ <button class="bar-item" onclick="openBar(event, 'unlisted')">Unlisted</button>
+ <button class="bar-item" onclick="openBar(event, 'legend')">Legend</button>
+</div>
+
+{% macro prettify_version(v) %}
+ <div class="version">
+ {% if v.epoch %}
+ <div class="v_epoch {{ v.epoch_status | make_status_class }}">{{ v.epoch }}</div>
+ <div class="colon">:</div>
+ {% endif %}
+ <div class="v_upstream {{ v.upstream_status | make_status_class }}">{{ v.upstream }}{{ v.upstream_rev }}</div>
+ {% if v.debian %}
+ <div class="dash">-</div>
+ <div class="v_debian {{ v.debian_status | make_status_class }}">{{ v.debian }}{{ v.debian_rev }}</div>
+ {% endif %}
+ {{ caller() }}
+ </div>
+{% endmacro %}
+
+{% macro render_package(pkg_name, dat, status_shown, action_shown, id_label) %}
+ <tr onclick="toggleClassByID('{{ id_label }}_{{ pkg_name }}_{{ status_shown }}_{{ action_shown }}')" id="{{ id_label }}_{{ pkg_name }}_{{ status_shown }}_{{ action_shown }}_button">
+ <td class="repo">{{ dat['desc']['repo'] }}</td>
+ <td class="component">{{ dat['desc']['component'] }}</td>
+ <td class="app">{{ dat['desc']['app'] }}</td>
+ <td class="package_name">{{ pkg_name }}</td>
+ <td class="status_container" colspan="3">
+ <div class="status {{ status_shown | make_status_class }}">{{ status_shown | make_status_label }}</div>
+ {% if action_shown | make_action_label %}
+ <div class="action {{ action_shown | make_action_class }}">{{ action_shown | make_action_label }}</div>
+ {% endif %}
+ </td>
+ </tr>
+ <tr class="collapsable" id="{{ id_label }}_{{ pkg_name }}_{{ status_shown }}_{{ action_shown }}"><td colspan="7">
+ <table class="nodes"><tbody>
+ {% for status in dat['results'].keys() | sort(reverse=true) %}
+ {% for action in dat['results'][status].keys() | sort(reverse=true) %}
+ {% set counter = 1 + loop.index0 %}
+ {% for node in dat['results'][status][action].keys() | sort %}
+ {% set n_counter = 1 + loop.index0 %}
+ {% set nd = dat['results'][status][action][node] %}
+ <tr>
+ <td class="repo">{{ n_counter }}</td>
+ <td class="node_name">{{ node }}</td>
+ <td class="status_container">
+ <div class="status {{ status | make_status_class }}">{{ status | make_status_label }}</div>
+ {% if action | make_action_label %}
+ <div class="action {{ action | make_action_class }}">{{ action | make_action_label }}</div>
+ {% endif %}
+ </td>
+ <td class="installed">
+ <div class="tooltip">
+ {% call prettify_version(nd['i']) %}
+ <pre class="tooltiptext">{{ nd['raw'] | linebreaks }}</pre>
+ {% endcall %}
+ </div>
+ </td>
+ <td class="candidate">{{ nd['c'].version }}</td>
+ <td class="release">{{ dat['r'].version }}</td>
+ </tr>
+ {% endfor %}
+ {% endfor %}
+ {% endfor %}
+ </tbody></table>
+ </td></tr>
+ {{ caller() }}
+{% endmacro %}
+
+{% macro package_table(pkg_dict, id_label) %}
+<div id="{{ id_label }}" class="barcontent">
+ <h5>{{ caller() }}</h5>
+ <table class="pkgversions">
+ <tbody>
+ <tr>
+ <td class="table_header" width="50px">repo</td>
+ <td class="table_header" width="130px">Component</td>
+ <td class="table_header" width="80px">App</td>
+ <td class="table_header" width="200px">Package name</td>
+ <td class="table_header">Installed</td>
+ <td class="table_header">Candidate</td>
+ <td class="table_header">Release</td>
+ </tr>
+ <!-- Print errors -->
+ <tr><td colspan="7">Errors ({{ errors[id_label] }})</td></tr>
+ {% for pkg_name in pkg_dict | get_sorted_keys %}
+ {% set dat = pkg_dict[pkg_name] %}
+ {% if status_err in dat['results'] %}
+ {% set action_to_show = dat['results'][status_err].keys() | get_max %}
+ {% call render_package(pkg_name, dat, status_err, action_to_show, id_label) %}
+ {% endcall %}
+ {% endif%}
+ {% endfor %}
+ {% if not errors[id_label] %}
+ <tr><td class="note" colspan="7">no errors found </td></tr>
+ {% endif %}
+
+ <!-- Print downgrades -->
+ <tr><td colspan="7">Downgrades ({{ downgrades[id_label] }})</td></tr>
+ {% for pkg_name in pkg_dict | get_sorted_keys %}
+ {% set dat = pkg_dict[pkg_name] %}
+ {% if status_down in dat['results'] %}
+ {% set action_to_show = dat['results'][status_down].keys() | get_max %}
+ {% call render_package(pkg_name, dat, status_down, action_to_show, id_label) %}
+ {% endcall %}
+ {% endif %}
+ {% endfor %}
+ {% if not downgrades[id_label] %}
+ <tr><td class="note" colspan="7">no downgrades found</td></tr>
+ {% endif %}
+
+ <!-- Print all other -->
+ <tr><td colspan="7">All others</td></tr>
+ {% for pkg_name in pkg_dict | get_sorted_keys %}
+ {% set dat = pkg_dict[pkg_name] %}
+ {% set status_to_show = dat['results'].keys() | get_max %}
+ {% set action_to_show = dat['results'][status_to_show].keys() | get_max %}
+ {% if status_err != status_to_show and status_down != status_to_show %}
+ {% call render_package(pkg_name, dat, status_to_show, action_to_show, id_label) %}
+ {% endcall %}
+ {% endif %}
+ {% endfor %}
+ </tbody>
+ </table>
+</div>
+{%- endmacro %}
+
+<!-- Mirantis packages which version is critical for functionality -->
+{% call package_table(critical, "mirantis") %}
+ Packages maintained and updated by Mirantis
+{% endcall %}
+
+<!-- System labeled packages-->
+{% call package_table(system, "system") %}
+ System packages which versions are critical to proper cloud function
+{%- endcall %}
+
+<!-- Other packages -->
+{% call package_table(other, "other") %}
+ Packages with no description or not critical
+{%- endcall %}
+
+{% call package_table(unlisted, "unlisted") %}
+ Packages that are not listed in version map. I.e. unexpected on the environment
+{%- endcall %}
+
+<!-- Legend -->
+<div id="legend" class="barcontent">
+ <h5>Legend: status and action explanation and possible combinations</h5>
+ <table class="pkgversions">
+ <tbody>
+ <tr><td colspan="7">Version status desctiptions</td></tr>
+ <tr>
+ <td class="status_container"><div class="status {{ cs.ok | make_status_class }}">{{ cs.ok | make_status_label }}</div></td>
+ <td>Installed and Candidate epoch:upstream version mach</td>
+ </tr>
+ <tr>
+ <td class="status_container"><div class="status {{ cs.up | make_status_class }}">{{ cs.up | make_status_label }}</div></td>
+ <td>Installed version is newer that the one found in Repo (i.e. candidate) or Release notes recordset</td>
+ </tr>
+ <tr>
+ <td class="status_container"><div class="status {{ cs.down | make_status_class }}">{{ cs.down | make_status_label }}</div></td>
+ <td>Installed version is older that the one found in Repo (i.e. candidate) or Release notes recordset</td>
+ </tr>
+ <tr>
+ <td class="status_container"><div class="status {{ cs.err | make_status_class }}">{{ cs.err | make_status_label }}</div></td>
+ <td>Installed version conflicts with a combination of Candidate and Release notes versions</td>
+ </tr>
+ <tr><td colspan="7">Action descriptions</td></tr>
+ <tr>
+ <td class="status_container"><div class="action {{ ca.na | make_action_class }}">{{ ca.na | make_action_label }} (no action)</div></td>
+ <td>No action suggested</td>
+ </tr>
+ <tr>
+ <td class="status_container"><div class="action {{ ca.up | make_action_class }}">{{ ca.up | make_action_label }}</div></td>
+ <td>There is an upgrade possible for the package. But it is not strictly required action.</td>
+ </tr>
+ <tr>
+ <td class="status_container"><div class="action {{ ca.need_up | make_action_class }}">{{ ca.need_up | make_action_label }}</div></td>
+ <td>Package should be upgraded to match version either in repo or in Release notes</td>
+ </tr>
+ <tr>
+ <td class="status_container"><div class="action {{ ca.need_down | make_action_class }}">{{ ca.need_down | make_action_label }}</div></td>
+ <td>Package should be downgraded to match version either in repo or in Release notes</td>
+ </tr>
+ <tr>
+ <td class="status_container"><div class="action {{ ca.repo | make_action_class }}">{{ ca.repo | make_action_label }}</div></td>
+ <td>Repo that is configured on the target node contains invalid version and should be updated</td>
+ </tr>
+ <tr><td colspan="7">Versions status and Action combinations</td></tr>
+ <tr>
+ <td class="status_container">
+ <div class="status {{ cs.err | make_status_class }}">{{ cs.err | make_status_label }}</div>
+ <div class="action {{ ca.repo | make_action_class }}">{{ ca.repo | make_action_label }}</div>
+ </td>
+ </tr>
+ </tbody></table>
+</div>
+</body>
+</html>
\ No newline at end of file
diff --git a/templates/pkg_versions_tmpl.j2 b/templates/pkg_versions_tmpl.j2
deleted file mode 100644
index b03e2ef..0000000
--- a/templates/pkg_versions_tmpl.j2
+++ /dev/null
@@ -1,327 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
-<head>
- <meta charset="UTF-8">
- <title>Cloud Package versions check</title>
- <style>
- body {
- font-family: Verdana, Geneva, Tahoma, sans-serif;
- font-size: 90% !important;
- }
- .dot_green {
- float: left;
- color: green;
- margin-right: 0.5em;
- margin-top: 0.2em;
- }
- .dot_red {
- float: left;
- color: red;
- margin-right: 0.5em;
- margin-top: 0.2em;
- }
- .dot_empty {
- float: left;
- color: darkgray;
- margin-right: 0.5em;
- margin-top: 0.2em;
- }
- /* Style the tab */
- .tab {
- float: left;
- width: 130px;
- border: 1px solid #fff;
- background-color: #efe;
- }
-
- /* Style the buttons that are used to open the tab content */
- .tab button {
- display: block;
- background-color: inherit;
- color: Black;
- border: none;
- outline: none;
- font-family: "Lucida Console", Monaco, monospace;
- text-align: left;
- cursor: pointer;
- transition: 0.3s;
- font-size: 1.1em;
- width: 100%;
- padding: 1px;
- margin: 1px;
- }
-
- button > div.node_name {
- float: left;
- font-size: 0.8em;
- }
-
- .smallgreytext {
- float: right;
- font-size: 0.5em;
- color: gray;
- }
-
- /* Change background color of buttons on hover */
- .tab button:hover {
- background-color: #7b7;
- }
-
- /* Create an active/current "tab button" class */
- .tab button.active {
- background-color: #8c8;
- color: white;
- }
-
- /* Style the tab content */
- .tabcontent {
- display: none;
- position: absolute;
- font-size: 1em;
- padding: 0.5em;
- right: -10%;
- top: 0%;
- transform: translateX(-12%);
- width: calc(100% - 170px);
- overflow-x: scroll;
- overflow-wrap: break-word;
- }
- .collapsable {
- visibility: collapse;
- display: none;
- }
-
- .collapsable.in {
- visibility: visible;
- display: table-row;
- }
-
- table {
- border: 0 hidden;
- width: 100%;
- }
- tr:nth-child(even) {
- background-color: #fff;
- }
- tr:nth-child(odd) {
- background-color: #ddd;
- }
- .Header {
- background-color: #bbb;
- color: Black;
- width: 30%;
- text-align: center;
- }
- .pkgName {
- font-size: 1em;
- padding-left: 10px;
- }
-
- .version {
- font-size: 1.1em;
- text-align: left;
- }
-
- .differ {
- background-color: #eaa;
- }
- /* Tooltip container */
- .tooltip {
- position: relative;
- display: inline-block;
- border-bottom: 1px dotted black;
- }
-
- .tooltip .tooltiptext {
- visibility: hidden;
- background-color: black;
- font-family: "Lucida Console", Monaco, monospace;
- font-size: 0.5em;
- width: auto;
- color: #fff;
- border-radius: 6px;
- padding: 5px 5px;
-
- /* Position the tooltip */
- position: absolute;
- z-index: 1;
- }
-
- .tooltip:hover .tooltiptext {
- visibility: visible;
- }
-
- </style>
- <script language="JavaScript">
- function toggleClassByID(pkg, number) {
- var elements = document.querySelectorAll("#"+pkg+"_"+number);
- var ii = elements.length;
- var button = document.querySelector("#"+pkg+"_button"+number);
-
- while (ii--) {
- if( elements[ii].className && elements[ii].className.indexOf("in") > -1 ) {
- elements[ii].classList.remove("in");
- button.innerHTML = "↑"
- }
- else {
- elements[ii].classList.add("in");
- button.innerHTML = "↓"
- }
- }
-
-
- }
- </script>
- <script language="JavaScript">
- function init() {
- // Declare all variables
- var i, tabcontent, tablinks;
-
- // Get all elements with class="tabcontent" and hide them
- tabcontent = document.getElementsByClassName("tabcontent");
- for (i = 1; i < tabcontent.length; i++) {
- tabcontent[i].style.display = "none";
- }
- tabcontent[0].style.display = "block";
-
- // Get all elements with class="tablinks" and remove the class "active"
- tablinks = document.getElementsByClassName("tablinks");
- for (i = 1; i < tablinks.length; i++) {
- tablinks[i].className = tablinks[i].className.replace(" active", "");
- }
- tablinks[0].className += " active";
-
- }
- function openTab(evt, tabName) {
- // Declare all variables
- var i, tabcontent, tablinks;
-
- // Get all elements with class="tabcontent" and hide them
- tabcontent = document.getElementsByClassName("tabcontent");
- for (i = 0; i < tabcontent.length; i++) {
- tabcontent[i].style.display = "none";
- }
-
- // Get all elements with class="tablinks" and remove the class "active"
- tablinks = document.getElementsByClassName("tablinks");
- for (i = 0; i < tablinks.length; i++) {
- tablinks[i].className = tablinks[i].className.replace(" active", "");
- }
-
- // Show the current tab, and add an "active" class to the link that opened the tab
- document.getElementById(tabName).style.display = "block";
- evt.currentTarget.className += " active";
- }
- </script>
-</head>
-<body onload="init()">
-<div class="tab">
- <button class="tablinks" onclick="openTab(event, 'All Diffs')")>
- <div class="node_name">All Diffs</div>
- </button>
-{% for node_name in nodes.keys() | sort %}
- {% if counters[node_name]['package_diff'] %}
- <button class="tablinks" onclick="openTab(event, '{{ node_name | shortname }}')">
- <div class="dot_green">●</div>
- <div class="node_name">{{ node_name | shortname }}</div>
- <div class="smallgreytext">({{ counters[node_name]['package_diff'] }} / {{ counters[node_name]['packages'] }})</div>
- </button>
- {% endif %}
-{% endfor %}
-{% for node_name in nodes.keys() | sort %}
- {% if not counters[node_name]['package_diff'] %}
- <button class="tablinks" onclick="openTab(event, '{{ node_name | shortname }}')">
- <div class="dot_empty">○</div>
- <div class="node_name">{{ node_name | shortname }}</div>
- <div class="smallgreytext">({{ counters[node_name]['package_diff'] }} / {{ counters[node_name]['packages'] }})</div>
- </button>
- {% endif %}
-{% endfor %}
-</div>
-<div id="All Diffs" class="tabcontent">
- <table class="pkgversions">
- <tbody>
- <tr>
- <td class="Header">Node name</td>
- <td class="Header">Installed</td>
- <td class="Header">Candidate</td>
- </tr>
- {% for pkg_name in pkg_diffs.keys() | sort %}
- {% if counters[pkg_name]['df_nodes'] %}
- {% set pkg_counter = 1 + loop.index0 %}
- <tr>
- <td>
- <a href="#" onclick="toggleClassByID('{{ pkg_name }}', '{{ pkg_counter }}')" id="{{ pkg_name }}_button{{ pkg_counter }}">↑</a>
- {{ pkg_name }}
- </td>
- <td>{{ counters[pkg_name]['df_nodes'] }}</td>
- <td></td>
- </tr>
- <tr><td colspan=3>
- <table class="nodes"><tbody>
- {% for node in pkg_diffs[pkg_name]['df_nodes'].keys() | sort %}
- <tr class="collapsable" id="{{ pkg_name }}_{{ pkg_counter }}">
- <td class="pkgName">{{ node }}</td>
- <td class="version differ">
- <div class="tooltip">{{ pkg_diffs[pkg_name]['df_nodes'][node]['i'] }}
- <pre class="tooltiptext">{{ pkg_diffs[pkg_name]['df_nodes'][node]['raw'] | linebreaks }}</pre>
- </div>
- </td>
- <td class="version">{{ pkg_diffs[pkg_name]['df_nodes'][node]['c'] }}</td>
- </tr>
- {% endfor %}
- </tbody></table>
- </td></tr>
- {% endif%}
- {% endfor %}
- </tbody>
- </table>
-</div>
-{% for node_name in nodes.keys() | sort %}
-<div id="{{ node_name | shortname }}" class="tabcontent">
- <table class="pkgversions">
- <tbody>
- <tr>
- <td class="Header">Package name</td>
- <td class="Header">Installed</td>
- <td class="Header">Candidate</td>
- </tr>
- <tr><td colspan=3>Package with different versions uniq for this node</td></tr>
- {% for package_name in nodes[node_name]['packages'] | sort %}
- {% if not nodes[node_name]['packages'][package_name]['is_equal'] %}
- {% if nodes[node_name]['packages'][package_name]['fail_uniq'] %}
- <tr>
- <td class="pkgName">{{ package_name }}</td>
- <td class="version differ">
- <div class="tooltip">{{ nodes[node_name]['packages'][package_name]['installed'] }}
- <pre class="tooltiptext">{{ nodes[node_name]['packages'][package_name]['raw'] | linebreaks }}</pre>
- </div>
- </td>
- <td class="version">{{ nodes[node_name]['packages'][package_name]['candidate'] }}</td>
- </tr>
- {% endif %}
- {% endif %}
- {% endfor %}
- <tr><td colspan=3>Packages with different versions on nodes with similar role</td></tr>
- {% for package_name in nodes[node_name]['packages'] | sort %}
- {% if not nodes[node_name]['packages'][package_name]['is_equal'] %}
- {% if not nodes[node_name]['packages'][package_name]['fail_uniq'] %}
- <tr>
- <td class="pkgName">{{ package_name }}</td>
- <td class="version differ">
- <div class="tooltip">{{ nodes[node_name]['packages'][package_name]['installed'] }}
- <pre class="tooltiptext">{{ nodes[node_name]['packages'][package_name]['raw'] | linebreaks }}</pre>
- </div>
- </td>
- <td class="version">{{ nodes[node_name]['packages'][package_name]['candidate'] }}</td>
- </tr>
- {% endif %}
- {% endif %}
- {% endfor %}
- <tr><td colspan=3>Packages with same versions (installed vs candidate): {{ counters[node_name]['package_eq'] }}</td></tr>
- </tbody>
- </table>
-</div>
-{% endfor %}
-</body>
-</html>
\ No newline at end of file