Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Foreman/Satellite el8toel9 upgrade #1181

Merged
merged 4 commits into from
May 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import glob
import os

from leapp.actors import Actor
from leapp.models import SatelliteFacts, SystemdServicesTasks
from leapp.tags import FactsPhaseTag, IPUWorkflowTag

SYSTEMD_WANTS_BASE = '/etc/systemd/system/multi-user.target.wants/'
SERVICES_TO_DISABLE = ['dynflow-sidekiq@*', 'foreman', 'foreman-proxy',
'httpd', 'postgresql', 'pulpcore-api', 'pulpcore-content',
'pulpcore-worker@*', 'tomcat', 'redis']


class SatelliteUpgradeServices(Actor):
evgeni marked this conversation as resolved.
Show resolved Hide resolved
"""
Reconfigure Satellite services
"""

name = 'satellite_upgrade_services'
consumes = (SatelliteFacts,)
produces = (SystemdServicesTasks,)
tags = (IPUWorkflowTag, FactsPhaseTag)

def process(self):
facts = next(self.consume(SatelliteFacts), None)
if not facts or not facts.has_foreman:
return

# disable services, will be re-enabled by the installer
services_to_disable = []
for service_name in SERVICES_TO_DISABLE:
for service in glob.glob(os.path.join(SYSTEMD_WANTS_BASE, '{}.service'.format(service_name))):
services_to_disable.append(os.path.basename(service))
self.produce(SystemdServicesTasks(to_disable=services_to_disable))
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import glob

from leapp.models import SatelliteFacts, SatellitePostgresqlFacts, SystemdServicesTasks


def test_disable_httpd(monkeypatch, current_actor_context):
def mock_glob():
orig_glob = glob.glob

def mocked_glob(pathname):
if pathname == '/etc/systemd/system/multi-user.target.wants/httpd.service':
return [pathname]
return orig_glob(pathname)

return mocked_glob

monkeypatch.setattr('glob.glob', mock_glob())

current_actor_context.feed(SatelliteFacts(has_foreman=True,
postgresql=SatellitePostgresqlFacts(local_postgresql=False)))
current_actor_context.run()

message = current_actor_context.consume(SystemdServicesTasks)[0]
assert 'httpd.service' in message.to_disable
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ def process(self):
run(['sed', '-i', '/data_directory/d', '/var/lib/pgsql/data/postgresql.conf'])
run(['systemctl', 'start', 'postgresql'])
run(['runuser', '-u', 'postgres', '--', 'reindexdb', '-a'])
if facts.postgresql.has_pulp_ansible_semver:
run(['runuser', '-c',
'echo "ALTER COLLATION pulp_ansible_semver REFRESH VERSION;" | psql pulpcore',
'postgres'])
except CalledProcessError as e:
api.current_logger().error('Failed to reindex the database: {}'.format(str(e)))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,21 @@ def test_run_reindexdb(monkeypatch, current_actor_context):
assert mocked_run.commands[1] == ['systemctl', 'start', 'postgresql']
assert mocked_run.commands[2] == ['runuser', '-u', 'postgres', '--', 'reindexdb', '-a']
assert mocked_run.commands[3] == ['foreman-installer', '--disable-system-checks']


def test_run_reindexdb_with_pulp_ansible(monkeypatch, current_actor_context):
mocked_run = MockedRun()
monkeypatch.setattr('leapp.libraries.stdlib.run', mocked_run)
current_actor_context.feed(SatelliteFacts(has_foreman=True,
postgresql=SatellitePostgresqlFacts(local_postgresql=True,
has_pulp_ansible_semver=True)))
current_actor_context.run()
assert mocked_run.commands
assert len(mocked_run.commands) == 5
assert mocked_run.commands[0] == ['sed', '-i', '/data_directory/d', '/var/lib/pgsql/data/postgresql.conf']
assert mocked_run.commands[1] == ['systemctl', 'start', 'postgresql']
assert mocked_run.commands[2] == ['runuser', '-u', 'postgres', '--', 'reindexdb', '-a']
assert mocked_run.commands[3] == ['runuser', '-c',
'echo "ALTER COLLATION pulp_ansible_semver REFRESH VERSION;" | psql pulpcore',
'postgres']
assert mocked_run.commands[4] == ['foreman-installer', '--disable-system-checks']
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ class SatellitePostgresqlFacts(Model):
""" How many bytes are required on the target partition """
space_available = fields.Nullable(fields.Integer())
""" How many bytes are available on the target partition """
has_pulp_ansible_semver = fields.Boolean(default=False)
""" Whether the DB has the pulp_ansible_semver collation """


class SatelliteFacts(Model):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,10 @@
POSTGRESQL_USER = 'postgres'
POSTGRESQL_GROUP = 'postgres'

SYSTEMD_WANTS_BASE = '/etc/systemd/system/multi-user.target.wants/'
SERVICES_TO_DISABLE = ['dynflow-sidekiq@*', 'foreman', 'foreman-proxy',
'httpd', 'postgresql', 'pulpcore-api', 'pulpcore-content',
'pulpcore-worker@*', 'tomcat']


class SatelliteUpgradeDataMigration(Actor):
"""
Reconfigure Satellite services and migrate PostgreSQL data
Migrate Satellite PostgreSQL data
"""

name = 'satellite_upgrade_data_migration'
Expand All @@ -32,14 +27,6 @@ def process(self):
if not facts or not facts.has_foreman:
return

# disable services, will be re-enabled by the installer
for service_name in SERVICES_TO_DISABLE:
for service in glob.glob(os.path.join(SYSTEMD_WANTS_BASE, '{}.service'.format(service_name))):
try:
os.unlink(service)
except Exception as e: # pylint: disable=broad-except
self.log.warning('Failed disabling service {}: {}'.format(service, e))

if facts.postgresql.local_postgresql and os.path.exists(POSTGRESQL_SCL_DATA_PATH):
# we can assume POSTGRESQL_DATA_PATH exists and is empty
# move PostgreSQL data to the new home
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
from leapp.actors import Actor
from leapp.libraries.common.config import architecture
from leapp.libraries.common.rpms import has_package
from leapp.models import (
InstalledRPM,
RepositoriesSetupTasks,
RpmTransactionTasks,
SatelliteFacts,
SatellitePostgresqlFacts,
UsedRepositories
)
from leapp.tags import FactsPhaseTag, IPUWorkflowTag

RELATED_PACKAGES = ('foreman', 'foreman-selinux', 'foreman-proxy', 'katello', 'katello-selinux',
'candlepin', 'candlepin-selinux', 'pulpcore-selinux', 'satellite', 'satellite-capsule')
RELATED_PACKAGE_PREFIXES = ('rubygem-hammer', 'rubygem-foreman', 'rubygem-katello',
'rubygem-smart_proxy', 'python3.11-pulp', 'foreman-installer',
'satellite-installer')


class SatelliteUpgradeFacts(Actor):
"""
Report which Satellite packages require updates and how to handle PostgreSQL data
"""

name = 'satellite_upgrade_facts'
consumes = (InstalledRPM, UsedRepositories)
produces = (RepositoriesSetupTasks, RpmTransactionTasks, SatelliteFacts)
tags = (IPUWorkflowTag, FactsPhaseTag)

def process(self):
if not architecture.matches_architecture(architecture.ARCH_X86_64):
return

has_foreman = has_package(InstalledRPM, 'foreman') or has_package(InstalledRPM, 'foreman-proxy')
if not has_foreman:
return

local_postgresql = has_package(InstalledRPM, 'postgresql-server')

to_install = ['rubygem-foreman_maintain']

for rpm_pkgs in self.consume(InstalledRPM):
for pkg in rpm_pkgs.items:
if pkg.name in RELATED_PACKAGES or pkg.name.startswith(RELATED_PACKAGE_PREFIXES):
to_install.append(pkg.name)

if local_postgresql:
to_install.extend(['postgresql', 'postgresql-server'])
if has_package(InstalledRPM, 'postgresql-contrib'):
to_install.append('postgresql-contrib')
if has_package(InstalledRPM, 'postgresql-evr'):
to_install.append('postgresql-evr')

self.produce(SatelliteFacts(
has_foreman=has_foreman,
has_katello_installer=False,
postgresql=SatellitePostgresqlFacts(
local_postgresql=local_postgresql,
has_pulp_ansible_semver=has_package(InstalledRPM, 'python3.11-pulp-ansible'),
),
))

repositories_to_enable = []
for used_repos in self.consume(UsedRepositories):
for used_repo in used_repos.repositories:
if used_repo.repository.startswith(('satellite-6', 'satellite-capsule-6', 'satellite-maintenance-6')):
repositories_to_enable.append(used_repo.repository.replace('for-rhel-8', 'for-rhel-9'))
if repositories_to_enable:
self.produce(RepositoriesSetupTasks(to_enable=repositories_to_enable))

self.produce(RpmTransactionTasks(to_install=to_install))
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
from leapp.libraries.common.config import mock_configs
from leapp.models import (
InstalledRPM,
RepositoriesSetupTasks,
RPM,
RpmTransactionTasks,
SatelliteFacts,
UsedRepositories,
UsedRepository
)

RH_PACKAGER = 'Red Hat, Inc. <http://bugzilla.redhat.com/bugzilla>'


def fake_package(pkg_name):
return RPM(name=pkg_name, version='0.1', release='1.sm01', epoch='1', packager=RH_PACKAGER, arch='noarch',
pgpsig='RSA/SHA256, Mon 01 Jan 1970 00:00:00 AM -03, Key ID 199e2f91fd431d51')


FOREMAN_RPM = fake_package('foreman')
FOREMAN_PROXY_RPM = fake_package('foreman-proxy')
KATELLO_INSTALLER_RPM = fake_package('foreman-installer-katello')
KATELLO_RPM = fake_package('katello')
RUBYGEM_KATELLO_RPM = fake_package('rubygem-katello')
RUBYGEM_FOREMAN_PUPPET_RPM = fake_package('rubygem-foreman_puppet')
POSTGRESQL_RPM = fake_package('postgresql-server')
SATELLITE_RPM = fake_package('satellite')
SATELLITE_CAPSULE_RPM = fake_package('satellite-capsule')
PULP_ANSIBLE_RPM = fake_package('python3.11-pulp-ansible')

SATELLITE_REPOSITORY = UsedRepository(repository='satellite-6.99-for-rhel-8-x86_64-rpms')
CAPSULE_REPOSITORY = UsedRepository(repository='satellite-capsule-6.99-for-rhel-8-x86_64-rpms')
MAINTENANCE_REPOSITORY = UsedRepository(repository='satellite-maintenance-6.99-for-rhel-8-x86_64-rpms')


def test_no_satellite_present(current_actor_context):
current_actor_context.feed(InstalledRPM(items=[]))
current_actor_context.run(config_model=mock_configs.CONFIG)
message = current_actor_context.consume(SatelliteFacts)
assert not message


def test_satellite_present(current_actor_context):
current_actor_context.feed(InstalledRPM(items=[FOREMAN_RPM]))
current_actor_context.run(config_model=mock_configs.CONFIG)
message = current_actor_context.consume(SatelliteFacts)[0]
assert message.has_foreman


def test_wrong_arch(current_actor_context):
current_actor_context.feed(InstalledRPM(items=[FOREMAN_RPM]))
current_actor_context.run(config_model=mock_configs.CONFIG_S390X)
message = current_actor_context.consume(SatelliteFacts)
assert not message


def test_satellite_capsule_present(current_actor_context):
current_actor_context.feed(InstalledRPM(items=[FOREMAN_PROXY_RPM]))
current_actor_context.run(config_model=mock_configs.CONFIG)
message = current_actor_context.consume(SatelliteFacts)[0]
assert message.has_foreman


def test_no_katello_installer_present(current_actor_context):
current_actor_context.feed(InstalledRPM(items=[FOREMAN_RPM]))
current_actor_context.run(config_model=mock_configs.CONFIG)
message = current_actor_context.consume(SatelliteFacts)[0]
assert not message.has_katello_installer


def test_katello_installer_present(current_actor_context):
current_actor_context.feed(InstalledRPM(items=[FOREMAN_RPM, KATELLO_INSTALLER_RPM]))
current_actor_context.run(config_model=mock_configs.CONFIG)
message = current_actor_context.consume(SatelliteFacts)[0]
# while the katello installer rpm is present, we do not want this to be true
# as the version in EL8 doesn't have the system checks we skip with this flag
assert not message.has_katello_installer


def test_installs_related_package(current_actor_context):
current_actor_context.feed(InstalledRPM(items=[FOREMAN_RPM, KATELLO_RPM, RUBYGEM_KATELLO_RPM,
RUBYGEM_FOREMAN_PUPPET_RPM]))
current_actor_context.run(config_model=mock_configs.CONFIG)
message = current_actor_context.consume(RpmTransactionTasks)[0]
assert 'katello' in message.to_install
assert 'rubygem-katello' in message.to_install
assert 'rubygem-foreman_puppet' in message.to_install


def test_installs_satellite_package(current_actor_context):
current_actor_context.feed(InstalledRPM(items=[FOREMAN_RPM, SATELLITE_RPM]))
current_actor_context.run(config_model=mock_configs.CONFIG)
message = current_actor_context.consume(RpmTransactionTasks)[0]
assert 'satellite' in message.to_install
assert 'satellite-capsule' not in message.to_install


def test_installs_satellite_capsule_package(current_actor_context):
current_actor_context.feed(InstalledRPM(items=[FOREMAN_PROXY_RPM, SATELLITE_CAPSULE_RPM]))
current_actor_context.run(config_model=mock_configs.CONFIG)
message = current_actor_context.consume(RpmTransactionTasks)[0]
assert 'satellite-capsule' in message.to_install
assert 'satellite' not in message.to_install


def test_detects_local_postgresql(current_actor_context):
current_actor_context.feed(InstalledRPM(items=[FOREMAN_RPM, POSTGRESQL_RPM]))
current_actor_context.run(config_model=mock_configs.CONFIG)

satellitemsg = current_actor_context.consume(SatelliteFacts)[0]
assert satellitemsg.postgresql.local_postgresql


def test_detects_remote_postgresql(current_actor_context):
current_actor_context.feed(InstalledRPM(items=[FOREMAN_RPM]))
current_actor_context.run(config_model=mock_configs.CONFIG)

satellitemsg = current_actor_context.consume(SatelliteFacts)[0]
assert not satellitemsg.postgresql.local_postgresql


def test_detects_pulp_ansible(current_actor_context):
current_actor_context.feed(InstalledRPM(items=[FOREMAN_RPM, POSTGRESQL_RPM, PULP_ANSIBLE_RPM]))
current_actor_context.run(config_model=mock_configs.CONFIG)

satellitemsg = current_actor_context.consume(SatelliteFacts)[0]
assert satellitemsg.postgresql.has_pulp_ansible_semver


def test_enables_right_repositories_on_satellite(current_actor_context):
current_actor_context.feed(InstalledRPM(items=[FOREMAN_RPM, SATELLITE_RPM]))
current_actor_context.feed(UsedRepositories(repositories=[SATELLITE_REPOSITORY, MAINTENANCE_REPOSITORY]))
current_actor_context.run(config_model=mock_configs.CONFIG)

rpmmessage = current_actor_context.consume(RepositoriesSetupTasks)[0]

assert 'satellite-maintenance-6.99-for-rhel-9-x86_64-rpms' in rpmmessage.to_enable
assert 'satellite-6.99-for-rhel-9-x86_64-rpms' in rpmmessage.to_enable
assert 'satellite-capsule-6.99-for-rhel-9-x86_64-rpms' not in rpmmessage.to_enable


def test_enables_right_repositories_on_capsule(current_actor_context):
current_actor_context.feed(InstalledRPM(items=[FOREMAN_PROXY_RPM, SATELLITE_CAPSULE_RPM]))
current_actor_context.feed(UsedRepositories(repositories=[CAPSULE_REPOSITORY, MAINTENANCE_REPOSITORY]))
current_actor_context.run(config_model=mock_configs.CONFIG)

rpmmessage = current_actor_context.consume(RepositoriesSetupTasks)[0]

assert 'satellite-maintenance-6.99-for-rhel-9-x86_64-rpms' in rpmmessage.to_enable
assert 'satellite-6.99-for-rhel-9-x86_64-rpms' not in rpmmessage.to_enable
assert 'satellite-capsule-6.99-for-rhel-9-x86_64-rpms' in rpmmessage.to_enable


def test_enables_right_repositories_on_upstream(current_actor_context):
current_actor_context.feed(InstalledRPM(items=[FOREMAN_RPM]))
current_actor_context.run(config_model=mock_configs.CONFIG)

message = current_actor_context.consume(RepositoriesSetupTasks)

assert not message
Loading