Skip to content
Open
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
155 changes: 155 additions & 0 deletions gpoa/apt1_runner
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
#!/usr/bin/python3
#
# GPOA - GPO Applier for Linux
#
# Copyright (C) 2025 BaseALT Ltd.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

import rpm
from gpoa.storage import registry_factory
from util.util import get_uid_by_username, string_to_literal_eval
import logging
from util.logging import log
import argparse
import gettext
import locale

import dbus
import dbus.mainloop.glib


def is_rpm_installed(rpm_name):
"""
Check if the package named 'rpm_name' is installed
"""
ts = rpm.TransactionSet()
pm = ts.dbMatch('name', rpm_name)
if pm.count() > 0:
return True

return False


def is_rpm_notinstalled(rpm_name):
"""
Check if the package named 'rpm_name' is not installed
"""
return not is_rpm_installed(rpm_name)


def remove_suffix(item):
return '-' + str(item)


class Apt_applier:
def __init__(self, user=None):
"""
Initialize the DBus client for org.altlinux.alterator.apt1

Throws:
dbus.exceptions.DBusException on error while connecting to the DBus
"""
dbus_interface = 'org.altlinux.alterator.apt1'
bus_name = 'org.altlinux.alterator'
object_path = '/org/altlinux/alterator/apt'

apt_obj = dbus.SystemBus().get_object(bus_name, object_path)
self.apt_iface = dbus.Interface(apt_obj, dbus_interface)

install_key_name = 'Install'
remove_key_name = 'Remove'
hklm_branch = 'Software/BaseALT/Policies/Packages'
self.storage = registry_factory()
if user:
uid = get_uid_by_username(user)
dict_dconf_db = self.storage.get_dictionary_from_dconf_file_db(uid)
else:
dict_dconf_db = self.storage.get_dictionary_from_dconf_file_db()
dict_packages = dict_dconf_db.get(hklm_branch, {})

self.remove_packages = set(map(str.strip, string_to_literal_eval(dict_packages.get(remove_key_name, []))))
self.install_packages = map(str.strip, string_to_literal_eval(dict_packages.get(install_key_name, [])))
self.install_packages = set(
filter(is_rpm_notinstalled, [item for item in self.install_packages if item not in self.remove_packages]))
self.remove_packages = filter(is_rpm_installed, self.remove_packages)

def apply(self):
"""
Call the ApplyAsync method for current packages policy
Throws:
dbus.exceptions.DBusException on error while connecting to the DBus
Returns:
response
"""
log('D235')

log('D148', {'names': self.install_packages})
log('D149', {'names': self.remove_packages})
response = self.apt_iface.ApplyAsync("' '",
"'" + " ".join(map(str, self.install_packages)) + " ".join(
map(remove_suffix, self.remove_packages)) + "'")
if response != 0:
remove_packages = filter(is_rpm_installed, self.remove_packages)
install_packages = filter(is_rpm_notinstalled, self.install_packages)
for package in remove_packages:
if self.apt_iface.ApplyAsync("' '", remove_suffix(package)) != 0:
log('E58', {'name': package})
for package in install_packages:
if self.apt_iface.ApplyAsync("' '", package) != 0:
log('E57', {'name': package})

return response

def update(self):
"""
Call the UpdateAsync method
Throws:
dbus.exceptions.DBusException on error while connecting to the DBus
Returns:
response
"""
response = self.apt_iface.UpdateAsync()
log('D143')
# TODO: Write output into log
return response


if __name__ == '__main__':
locale.bindtextdomain('gpoa', '/usr/lib/python3/site-packages/gpoa/locale')
gettext.bindtextdomain('gpoa', '/usr/lib/python3/site-packages/gpoa/locale')
gettext.textdomain('gpoa')
logger = logging.getLogger()
parser = argparse.ArgumentParser(description='Package applier')
parser.add_argument('--user', type=str, help='user', nargs='?', default=None)
parser.add_argument('--loglevel', type=int, help='loglevel', nargs='?', default=30)

dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)

args = parser.parse_args()
logger.setLevel(args.loglevel)

try:
if args.user:
applier = Apt_applier(args.user)
else:
applier = Apt_applier()
except dbus.exceptions.DBusException as e:
exit(1)

try:
if applier.apply() != 0:
exit(1)
except dbus.exceptions.DBusException as exc:
exit(1)
53 changes: 47 additions & 6 deletions gpoa/frontend/package_applier.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,20 @@
applier_frontend
, check_enabled
)
import os

def select_runner() -> None | str:
"""
Select runner to use for package applier

Returns:
str if backend is selected
None otherwise
"""
proc = subprocess.run(['/usr/libexec/gpupdate/select_runner'], stdout=subprocess.PIPE)
if proc.returncode != 0:
return None
return proc.stdout.decode('utf-8').strip()

class package_applier(applier_frontend):
__module_name = 'PackagesApplier'
Expand All @@ -40,8 +54,16 @@ def __init__(self, storage):
install_branch = '{}\\{}%'.format(self.__hklm_branch, self.__install_key_name)
remove_branch = '{}\\{}%'.format(self.__hklm_branch, self.__remove_key_name)
sync_branch = '{}\\{}%'.format(self.__hklm_branch, self.__sync_key_name)

runner = select_runner()
if runner is None:
log('E81')
raise Exception('No package runner selected')
log('D236', {'runner': runner})
self.runner = runner + '_runner'

self.fulcmd = []
self.fulcmd.append('/usr/libexec/gpupdate/pkcon_runner')
self.fulcmd.append('/usr/libexec/gpupdate/' + self.runner)
self.fulcmd.append('--loglevel')
logger = logging.getLogger()
self.fulcmd.append(str(logger.level))
Expand All @@ -65,13 +87,19 @@ def run(self):
subprocess.check_call(self.fulcmd)
except Exception as exc:
logdata = {'msg': str(exc)}
log('E55', logdata)
if self.runner == 'pkcon_runner':
log('E55', logdata)
elif self.runner == 'apt1_runner':
log('E79', logdata)
else:
try:
subprocess.Popen(self.fulcmd,close_fds=False)
except Exception as exc:
logdata = {'msg': str(exc)}
log('E61', logdata)
if self.runner == 'pkcon_runner':
log('E61', logdata)
elif self.runner == 'apt1_runner':
log('E80', logdata)

def apply(self):
if self.__module_enabled:
Expand All @@ -91,10 +119,17 @@ class package_applier_user(applier_frontend):
__hkcu_branch = 'Software\\BaseALT\\Policies\\Packages'

def __init__(self, storage, username):
runner = select_runner()
if runner is None:
log('E81')
raise Exception('No package applier runner found')
log('D236', {'runner': runner})
self.runner = runner + '_runner'

self.storage = storage
self.username = username
self.fulcmd = []
self.fulcmd.append('/usr/libexec/gpupdate/pkcon_runner')
self.fulcmd.append('/usr/libexec/gpupdate/' + self.runner)
self.fulcmd.append('--user')
self.fulcmd.append(self.username)
self.fulcmd.append('--loglevel')
Expand Down Expand Up @@ -129,13 +164,19 @@ def run(self):
subprocess.check_call(self.fulcmd)
except Exception as exc:
logdata = {'msg': str(exc)}
log('E60', logdata)
if self.runner == 'pkcon_runner':
log('E60', logdata)
elif self.runner == 'apt1_runner':
log('E77', logdata)
else:
try:
subprocess.Popen(self.fulcmd,close_fds=False)
except Exception as exc:
logdata = {'msg': str(exc)}
log('E62', logdata)
if self.runner == 'pkcon_runner':
log('E62', logdata)
elif self.runner == 'apt1_runner':
log('E78', logdata)

def admin_context_apply(self):
'''
Expand Down
21 changes: 21 additions & 0 deletions gpoa/locale/ru_RU/LC_MESSAGES/gpoa.po
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,21 @@ msgstr "Не удалось обновить LDAP новыми данными п
msgid "Failed to change local user password"
msgstr "Не удалось изменить пароль локального пользователя"

msgid "Error running apt1_runner sync for user"
msgstr "Ошибка при запуске apt1_runner синхронно для пользователя"

msgid "Error running apt1_runner async for user"
msgstr "Ошибка при запуске apt1_runner асинхронно для пользователя"

msgid "Error running apt1_runner sync for machine"
msgstr "Ошибка при запуске apt1_runner синхронно для компьютера"

msgid "Error running apt1_runner async for machine"
msgstr "Ошибка при запуске apt1_runner асинхронно для компьютера"

msgid "Error no package applier runner found"
msgstr "Ошибка не найден исполнитель применения пакетов"

# Error_end

# Debug
Expand Down Expand Up @@ -958,6 +973,12 @@ msgstr "Расчет времени с момента первого входа
msgid "No logins found after password change"
msgstr "Не найдены входы после изменения пароля"

msgid "Running apt1_runner to install and remove packages"
msgstr "Запуск apt1_runner для установки и удаления пакетов"

msgid "Package applier runner found"
msgstr "Найдено средство применения пакета"

msgid "Unknown message type, no message assigned"
msgstr "Неизвестный тип сообщения"

Expand Down
8 changes: 8 additions & 0 deletions gpoa/messages/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,12 @@ def error_code(code):
error_ids[74] = 'Autofs restart failed'
error_ids[75] = 'Failed to update LDAP with new password data'
error_ids[76] = 'Failed to change local user password'
error_ids[77] = 'Error running apt1_runner sync for user'
error_ids[78] = 'Error running apt1_runner async for user'
error_ids[79] = 'Error running apt1_runner sync for machine'
error_ids[80] = 'Error running apt1_runner async for machine'
error_ids[81] = 'Error no package applier runner found'

return error_ids.get(code, 'Unknown error code')

def debug_code(code):
Expand Down Expand Up @@ -349,6 +355,8 @@ def debug_code(code):
debug_ids[232] = 'No user login records found'
debug_ids[233] = 'Calculating time since the first user login after their password change'
debug_ids[234] = 'No logins found after password change'
debug_ids[235] = 'Running apt1_runner to install and remove packages'
debug_ids[236] = 'Package applier runner found'

return debug_ids.get(code, 'Unknown debug code')

Expand Down
Loading