"""
Satellite PostgreSQL database queries
=====================================
This module contains the following parsers:
SatelliteAdminSettings - command ``psql -d foreman -c 'select name, value, "default" from settings where name in (\'destroy_vm_on_host_delete\', \'unregister_delete_host\') --csv'``
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SatelliteComputeResources - command ``psql -d foreman -c 'select name, type from compute_resources' --csv``
-----------------------------------------------------------------------------------------------------------
SatelliteCoreTaskReservedResourceCount - command ``psql -d pulpcore -c 'select count(*) from core_taskreservedresource' --csv``
-------------------------------------------------------------------------------------------------------------------------------
SatelliteKatellloReposWithMultipleRef - command ``psql -d foreman -c "select repository_href, count(*) from katello_repository_references group by repository_href having count(*) > 1;" --csv``
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SatelliteQualifiedCapsules - command ``psql -d foreman -c "select name from smart_proxies where download_policy = 'background'" --csv``
---------------------------------------------------------------------------------------------------------------------------------------
SatelliteQualifiedKatelloRepos - command ``psql -d foreman -c "select id, name, url, download_policy from katello_root_repositories where download_policy = 'background' or url is NULL" --csv``
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SatelliteSCAStatus - command ``psql -d candlepin -c "select displayname, content_access_mode from cp_owner" --csv``
-------------------------------------------------------------------------------------------------------------------
"""
import os
import yaml
from csv import DictReader
from insights import parser, CommandParser
from insights.specs import Specs
from insights.parsers import SkipException, ParseException
from insights.parsers import keyword_search, calc_offset
from insights.util import deprecated
[docs]class SatellitePostgreSQLQuery(CommandParser, list):
"""
Parent class of satellite postgresql table queries. It can not be used
directly, A child class with overriding columns attribute is required.
It saves the rows data into a list. Each row is saved into a dict.
The key is the column name, the value is the value of the column.
Resultant data structure::
[
{
'name': 'abc',
'url': '',
'value': 'test'
},
{
'name': 'def',
'url': 'http://xx.com',
'value': ''
}
]
Sample Output::
name,url,value
abc,,test
def,http://xx.com,
Raises:
SkipException: when there isn't data in the table
ParseException: when the output isn't in good csv format.
NotImplementedError: when the subclass doesn't override the columns attribute.
"""
# child class should override the columns attribute with its own column names
columns = []
[docs] def parse_content(self, content):
if not self.columns:
raise NotImplementedError("Please override the columns attribute.")
start_index = calc_offset(content, self.columns, require_all=True)
if 'Last login:' in content[-1]:
valid_lines = content[start_index:-1]
else:
valid_lines = content[start_index:]
reader = DictReader(os.linesep.join(valid_lines).splitlines(True))
for row in reader:
self.append(row)
if not self:
raise SkipException("There is no data in the table.")
[docs] def search(self, **kwargs):
"""
Get the rows by searching the table with kwargs.
This uses the :py:func:`insights.parsers.keyword_search` function for
searching; see its documentation for usage details. If no search
parameters are given, no rows are returned.
It simplify the value of the column according to actual usage.
Returns:
list: A list of dictionaries of rows that match the given
search criteria.
"""
return keyword_search(self, **kwargs)
[docs]@parser(Specs.satellite_settings)
class SatelliteAdminSettings(SatellitePostgreSQLQuery):
"""
Parse the output of the command ``psql -d foreman -c '"select name, value, "default" from settings where name in ('destroy_vm_on_host_delete', 'unregister_delete_host') --csv"``.
Sample output::
name,value,default
unregister_delete_host,"--- true
...","--- false
..."
destroy_vm_on_host_delete,,"--- true
..."
Examples:
>>> type(table)
<class 'insights.parsers.satellite_postgresql_query.SatelliteAdminSettings'>
>>> table.get_setting('unregister_delete_host')
True
>>> table.get_setting('destroy_vm_on_host_delete')
True
"""
columns = ['name', 'value', 'default']
def _parse_yaml(self, value):
if value:
try:
return yaml.safe_load(value)
except Exception:
raise ParseException("Bad format value: %s" % value)
return value
[docs] def parse_content(self, content):
"""
The "default" and "value" columns must be selected, or else the
settings value can't be determined.
The "default" and "value" column are in yaml format, it is transfer to
python object.
Raises:
SkipException: when value or default column isn't found in the
table.
ParseException: when the value or default in bad yaml format.
"""
super(SatelliteAdminSettings, self).parse_content(content)
for row in self:
row['default'] = self._parse_yaml(row['default'])
row['value'] = self._parse_yaml(row['value'])
[docs] def get_setting(self, setting_name):
"""
Get the actual value of setting_name.
If the value column isn't empty, the value of the setting_name is the
value column, or else it's the default column.
Args:
setting_name (str): the value of name column which is searched in the table.
Returns:
It depends on the setting, maybe boolean, string, int or a list.
None if the setting_name doesn't exist in the table.
"""
rows = self.search(name=setting_name)
if rows:
value = rows[0].get('value')
return rows[0].get('default') if value == '' else value
[docs]@parser(Specs.satellite_compute_resources)
class SatelliteComputeResources(SatellitePostgreSQLQuery):
"""
Parse the output of the command ``psql -d foreman -c 'select name, type from compute_resources' --csv``.
Sample output::
name,type
test_compute_resource1,Foreman::Model::Libvirt
test_compute_resource2,Foreman::Model::RHV
Examples:
>>> type(resources_table)
<class 'insights.parsers.satellite_postgresql_query.SatelliteComputeResources'>
>>> rows=resources_table.search(type='Foreman::Model::Libvirt')
>>> len(rows)
1
>>> rows[0]['name']
'test_compute_resource1'
"""
columns = ['name', 'type']
[docs]@parser(Specs.satellite_core_taskreservedresource_count)
class SatelliteCoreTaskReservedResourceCount(SatellitePostgreSQLQuery):
"""
Parse the output of the command ``psql -d pulpcore -c 'select count(*) from core_taskreservedresource' --csv``.
Sample output::
count
0
Examples:
>>> type(tasks)
<class 'insights.parsers.satellite_postgresql_query.SatelliteCoreTaskReservedResourceCount'>
>>> tasks[0]['count']
'0'
"""
columns = ['count']
[docs]@parser(Specs.satellite_katello_empty_url_repositories)
class SatelliteKatelloEmptyURLRepositories(SatellitePostgreSQLQuery):
"""
.. warning::
This parser is deprecated, please use
:py:class:`insights.parsers.satellite_postgresql_query.SatelliteQualifiedKatelloRepos` instead.
Parse the output of the command ``psql -d foreman -c 'select id, name from katello_root_repositories where url is NULL;' --csv``.
Sample output::
id,name
54,testa
55,testb
Examples:
>>> type(katello_root_repositories)
<class 'insights.parsers.satellite_postgresql_query.SatelliteKatelloEmptyURLRepositories'>
>>> len(katello_root_repositories)
2
>>> katello_root_repositories[0]['name']
'testa'
"""
columns = ['id', 'name']
def __init__(self, *args, **kwargs):
deprecated(SatelliteKatelloEmptyURLRepositories, 'Please use the SatelliteQualifiedKatelloRepos parser in the current module.')
super(SatelliteKatelloEmptyURLRepositories, self).__init__(*args, **kwargs)
[docs]@parser(Specs.satellite_katello_repos_with_muliple_ref)
class SatelliteKatellloReposWithMultipleRef(SatellitePostgreSQLQuery):
"""
Parse the output of the command ``psql -d foreman -c "select repository_href, count(*) from katello_repository_references group by repository_href having count(*) > 1;" --csv``.
Sample output::
repository_href,count
/pulp/api/v3/repositories/rpm/rpm/64e1ddf8-025e-45f2-b2f0-04b874674671/,3
/pulp/api/v3/repositories/rpm/rpm/sfwrsrw45sfse-45f2-b2f0-04b874675688/,2
Examples:
>>> type(multi_ref_katello_repos)
<class 'insights.parsers.satellite_postgresql_query.SatelliteKatellloReposWithMultipleRef'>
>>> len(multi_ref_katello_repos)
2
>>> multi_ref_katello_repos[0]['repository_href']
'/pulp/api/v3/repositories/rpm/rpm/64e1ddf8-025e-45f2-b2f0-04b874674671/'
"""
columns = ['repository_href', 'count']
[docs]@parser(Specs.satellite_qualified_katello_repos)
class SatelliteQualifiedKatelloRepos(SatellitePostgreSQLQuery):
"""
Parse the output of the command ``psql -d foreman -c "select id, name, url, download_policy from katello_root_repositories where download_policy = 'background' or url is NULL" --csv``.
Sample output::
id,name,url,download_policy
2,Red Hat Satellite Tools 6.8 for RHEL 7 Server RPMs x86_64,,on_demand
3,Red Hat Enterprise Linux 8 for x86_64 - AppStream RPMs 8,https://cdn.redhat.com/content/dist/rhel8/8/x86_64/appstream/os,background
4,Red Hat Enterprise Linux 7 Server RPMs x86_64 7Server,https://cdn.redhat.com/content/dist/rhel/server/7/7Server/x86_64/os,background
Examples:
>>> type(repos)
<class 'insights.parsers.satellite_postgresql_query.SatelliteQualifiedKatelloRepos'>
>>> len(repos)
3
>>> repos[0]['name']
'Red Hat Satellite Tools 6.8 for RHEL 7 Server RPMs x86_64'
"""
columns = ['id', 'name', 'url', 'download_policy']
[docs]@parser(Specs.satellite_qualified_capsules)
class SatelliteQualifiedCapsules(SatellitePostgreSQLQuery):
"""
Parse the output of the command ``psql -d foreman -c "select name from smart_proxies where download_policy = 'background'" --csv``.
Sample output::
name
capsule1.test.com
capsule2.test.com
Examples:
>>> type(capsules)
<class 'insights.parsers.satellite_postgresql_query.SatelliteQualifiedCapsules'>
>>> len(capsules)
2
>>> capsules[0]['name']
'capsule1.test.com'
"""
columns = ['name']
[docs]@parser(Specs.satellite_sca_status)
class SatelliteSCAStatus(SatellitePostgreSQLQuery):
"""
Parse the output of the command ``psql -d candlepin -c "select displayname, content_access_mode from cp_owner" --csv``.
Sample output::
displayname,content_access_mode
Default Organization,entitlement
Orgq,org_environment
Examples:
>>> type(sat_sca_info)
<class 'insights.parsers.satellite_postgresql_query.SatelliteSCAStatus'>
>>> sat_sca_info.sca_enabled
True
"""
columns = ['displayname', 'content_access_mode']
@property
def sca_enabled(self):
"""
If the value of content_access_mode is "org_environment", it means the SCA is enabled for this organization.
Return True if any organization has SCA enabled on the satellite else False
"""
return bool(len(self.search(content_access_mode='org_environment')))