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

[OSMorphing] Check installed packages before installing packages #337

Merged
merged 2 commits into from
Sep 16, 2024

Conversation

Cristi1324
Copy link
Contributor

This PR adds check_installed_package for Redhat, Debian and SUSE.

@@ -122,6 +122,14 @@ def set_net_config(self, nics_info, dhcp):
cfg_name = "%s/coriolis_netplan.yaml" % netplan_base
self._write_file_sudo(cfg_name, new_cfg)

def check_installed_package(self, package_name):
cmd = 'dpkg-query -W %s' % ("".join(package_name))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be better to just send a single command that lists all the packages installed on the migrated system. Parse that list and save it on the tools object. Then when you need to check a package, you just do a if package in self.installed_packages: return or do a set difference like below to get the list of packages that need to be installed.

The point of this is to send a minimum amount of SSH commands, instead of sending N+1commands for each package we want to install. For Debian-based, you can use apt list --installed, please check a command for the others too.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You also don't need to "".join(package_name) here, you can simply pass the string value to the string format.

@Cristi1324 Cristi1324 force-pushed the check_installed_packages branch 8 times, most recently from fc8e18b to b234a6f Compare September 2, 2024 12:46
@@ -122,6 +122,13 @@ def set_net_config(self, nics_info, dhcp):
cfg_name = "%s/coriolis_netplan.yaml" % netplan_base
self._write_file_sudo(cfg_name, new_cfg)

def get_installed_packages(self):
cmd = 'apt list --installed'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method has incomplete parsing in my opinion. I expected a list of package names, you returned a list of package names plus some other information. Please properly parse that list before returning it. Therefore please try the following:
All apt list --installed lists packages in this format:

package_name/repo,version,etc

You could split this and only get the package name:

apt_list_output = self._exec_cmd_chroot(cmd).splitlines() # and maybe also a .decode(), not 100% sure
for line in apt_list_output:
    package_name, _ = line.split('/', 1)
    self.installed_packages.append(package_name)
# you don't need to return anything, I'd much rather do a set difference between installed_packages and
# packages_add inside (or before) install_packages. The upside to this is that you can switfly check packages
# in other places too (ex. if 'grubby' not in self.installed_packages: self._install(['grubby']).

@@ -239,6 +239,10 @@ def morph_image(origin_provider, destination_provider, connection_info,
LOG.info("Post packages uninstall")
export_os_morphing_tools.post_packages_uninstall(packages_remove)

LOG.info("Checking for packages already installed")
packages_add = import_os_morphing_tools.check_installed_packages(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can replace this with calling get_installed_packages, and then only install the set difference

def _has_package_installed(self, package_name):
cmd = 'rpm -q %s' % ("".join(package_name))
def get_installed_packages(self):
cmd = 'rpm -qa'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can finetune this command also to only get the list of package names:

rpm -qa --qf '%{NAME}\n'

@@ -295,7 +294,7 @@ def pre_packages_install(self, package_names):
super(BaseRedHatMorphingTools, self).pre_packages_install(
package_names)
self._yum_clean_all()
if not self._has_package_installed('grubby'):
if not any('grubby' in package for package in self.installed_packages):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As mentioned above, you can just check if 'grubbyis inself.installed_packages`. Do please check the package name string as a whole, as this could have buggy results. Let's say your list has a package called 'grubby-somethhing', but you need 'grubby' package instead, this code would skip that install.

@@ -65,6 +65,15 @@ def set_net_config(self, nics_info, dhcp):
# TODO(alexpilotti): add networking support
pass

def get_installed_packages(self):
cmd = 'rpm -qa'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make this the same as redhat please.

@Cristi1324 Cristi1324 force-pushed the check_installed_packages branch 4 times, most recently from 91b2075 to 2ca7cb4 Compare September 4, 2024 11:47
def _has_package_installed(self, package_name):
cmd = 'rpm -q %s' % ("".join(package_name))
def get_installed_packages(self):
cmd = 'rpm -qa --qf \'%{NAME}\n\''
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is most probably going to fail. If it does, please try:

cmd = 'rpm -qa --qf "%{NAME}\\n"'

@Cristi1324 Cristi1324 force-pushed the check_installed_packages branch 14 times, most recently from e290ed8 to 96f506b Compare September 5, 2024 11:30
@@ -122,6 +122,17 @@ def set_net_config(self, nics_info, dhcp):
cfg_name = "%s/coriolis_netplan.yaml" % netplan_base
self._write_file_sudo(cfg_name, new_cfg)

def get_installed_packages(self):
cmd = "apt list --installed 2>/dev/null | awk -F/ '{print $1}'"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can remove the 2>/dev/null as stderr is returned elsewhere, and will not be included in apt_list_output

def get_installed_packages(self):
cmd = "dpkg-query -f '${binary:Package}\n' -W"
try:
apt_list_output = self._exec_cmd_chroot(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, could you please check whether you could do the following:

apt_list_output = self._exec_cmd_chroot(cmd).decode().splitlines()

This way, you only call for decode() once.

@@ -239,6 +239,13 @@ def morph_image(origin_provider, destination_provider, connection_info,
LOG.info("Post packages uninstall")
export_os_morphing_tools.post_packages_uninstall(packages_remove)

LOG.info("Checking for packages already installed")
import_os_morphing_tools.get_installed_packages()
LOG.info("Packages already installed: %s" %
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could be a big list, please remove it.

self._exec_cmd_chroot(cmd)
return True
apt_list_output = self._exec_cmd_chroot(
cmd).splitlines()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above about the decode()

cmd = 'rpm -qa --qf \'%{NAME}\n\''
try:
apt_list_output = self._exec_cmd_chroot(
cmd).splitlines()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above about the decode()

@Cristi1324 Cristi1324 force-pushed the check_installed_packages branch 2 times, most recently from 1619902 to 4bea23c Compare September 9, 2024 09:41
Copy link
Contributor

@Dany9966 Dany9966 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. If your testing also looks good, please go ahead and update the unit tests also.

Copy link
Contributor

@Dany9966 Dany9966 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! Thank you!

@Dany9966 Dany9966 merged commit 87d3541 into cloudbase:master Sep 16, 2024
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants