def replace_rpm_package(package): """Replaced rpm package.rpm on master node with package.rpm from review """ ssh = SSHManager() logger.info("Patching {}".format(package)) if not settings.UPDATE_FUEL: raise exceptions.FuelQAVariableNotSet('UPDATE_FUEL', 'True') try: # Upload package target_path = '/var/www/nailgun/{}/'.format(package) ssh.upload_to_remote(ip=ssh.admin_ip, source=settings.UPDATE_FUEL_PATH.rstrip('/'), target=target_path) package_name = package package_ext = '*.noarch.rpm' pkg_path = os.path.join(target_path, '{}{}'.format(package_name, package_ext)) full_package_name = get_full_filename(wildcard_name=pkg_path) logger.debug('Package name is {0}'.format(full_package_name)) full_package_path = os.path.join(os.path.dirname(pkg_path), full_package_name) # Update package on master node if not does_new_pkg_equal_to_installed_pkg( installed_package=package_name, new_package=full_package_path): update_rpm(path=full_package_path) except Exception: logger.error("Could not upload package") raise
def replace_rpm_package(package): """Replaced rpm package.rpm on master node with package.rpm from review """ ssh = SSHManager() logger.info("Patching {}".format(package)) if not settings.UPDATE_FUEL: raise exceptions.FuelQAVariableNotSet('UPDATE_FUEL', 'True') try: # Upload package target_path = '/var/www/nailgun/{}/'.format(package) ssh.upload_to_remote( ip=ssh.admin_ip, source=settings.UPDATE_FUEL_PATH.rstrip('/'), target=target_path) package_name = package package_ext = '*.noarch.rpm' pkg_path = os.path.join(target_path, '{}{}'.format(package_name, package_ext)) full_package_name = get_full_filename(wildcard_name=pkg_path) logger.debug('Package name is {0}'.format(full_package_name)) full_package_path = os.path.join(os.path.dirname(pkg_path), full_package_name) # Update package on master node if not does_new_pkg_equal_to_installed_pkg( installed_package=package_name, new_package=full_package_path): update_rpm(path=full_package_path) except Exception: logger.error("Could not upload package") raise
def update_ostf(): logger.info("Uploading new package from {0}".format( settings.UPDATE_FUEL_PATH)) ssh = SSHManager() pack_path = '/var/www/nailgun/fuel-ostf/' full_pack_path = os.path.join(pack_path, 'fuel-ostf*.noarch.rpm') ssh.upload_to_remote( ssh.admin_ip, source=settings.UPDATE_FUEL_PATH.rstrip('/'), target=pack_path) # Check old fuel-ostf package cmd = "rpm -q fuel-ostf" old_package = ssh.execute_on_remote(ssh.admin_ip, cmd=cmd)['stdout_str'] logger.info( 'Current package version of ' 'fuel-ostf: {0}'.format(old_package)) cmd = "rpm -qp {0}".format(full_pack_path) new_package = ssh.execute_on_remote(ssh.admin_ip, cmd=cmd)['stdout_str'] logger.info('Package from review {0}'.format(new_package)) if old_package == new_package: logger.info('Package {0} is installed'.format(new_package)) return cmd = "service ostf stop" ssh.execute_on_remote(ssh.admin_ip, cmd=cmd) cmd = "service ostf status" helpers.wait(lambda: "dead" in ssh.execute_on_remote( ssh.admin_ip, cmd=cmd, raise_on_assert=False, assert_ec_equal=[3])['stdout_str'], timeout=60) logger.info("OSTF status: inactive") cmd = "rpm -e fuel-ostf" ssh.execute_on_remote(ssh.admin_ip, cmd=cmd) cmd = "rpm -Uvh --oldpackage {0}".format(full_pack_path) ssh.execute_on_remote(ssh.admin_ip, cmd=cmd) cmd = "rpm -q fuel-ostf" installed_package = ssh.execute_on_remote( ssh.admin_ip, cmd=cmd)['stdout_str'] assert_equal( installed_package, new_package, "The new package {0} was not installed. Actual {1}".format( new_package, installed_package)) cmd = "service ostf start" ssh.execute_on_remote(ssh.admin_ip, cmd=cmd) cmd = "service ostf status" helpers.wait( lambda: "running" in ssh.execute_on_remote(ssh.admin_ip, cmd=cmd)['stdout_str'], timeout=60) cmd = "curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:8777" helpers.wait( lambda: "401" in ssh.execute_on_remote( ssh.admin_ip, cmd=cmd, raise_on_assert=False)['stdout_str'], timeout=60) logger.info("OSTF status: RUNNING")
def centos_setup_fuel(self, hostname): logger.info("upload fuel-release packet") if not settings.FUEL_RELEASE_PATH: raise exceptions.FuelQAVariableNotSet('FUEL_RELEASE_PATH', '/path') try: ssh = SSHManager() pack_path = '/tmp/' full_pack_path = os.path.join(pack_path, 'fuel-release*.noarch.rpm') ssh.upload_to_remote( ip=ssh.admin_ip, source=settings.FUEL_RELEASE_PATH.rstrip('/'), target=pack_path) except Exception: logger.exception("Could not upload package") logger.debug("Update host information") cmd = "echo HOSTNAME={} >> /etc/sysconfig/network".format(hostname) ssh.execute_on_remote(ssh.admin_ip, cmd=cmd) cmd = "echo {0} {1} {2} >> /etc/hosts".format( ssh.admin_ip, hostname, settings.FUEL_MASTER_HOSTNAME) ssh.execute_on_remote(ssh.admin_ip, cmd=cmd) cmd = "hostname {}".format(hostname) ssh.execute_on_remote(ssh.admin_ip, cmd=cmd) logger.debug("setup MOS repositories") cmd = "rpm -ivh {}".format(full_pack_path) ssh.execute_on_remote(ssh.admin_ip, cmd=cmd) cmd = "yum install -y fuel-setup" ssh.execute_on_remote(ssh.admin_ip, cmd=cmd) cmd = "yum install -y screen" ssh.execute_on_remote(ssh.admin_ip, cmd=cmd) logger.info("Install Fuel services") cmd = "screen -dm bash -c 'showmenu=no wait_for_external_config=yes " \ "bootstrap_admin_node.sh'" ssh.execute_on_remote(ssh.admin_ip, cmd=cmd) self.env.wait_for_external_config() self.env.admin_actions.modify_configs(self.env.d_env.router()) self.env.kill_wait_for_external_config() self.env.wait_bootstrap() logger.debug("Check Fuel services") self.env.admin_actions.wait_for_fuel_ready() logger.debug("post-installation configuration of Fuel services") self.fuel_post_install_actions()
def update_ostf(): logger.info("Uploading new package from {0}".format( settings.UPDATE_FUEL_PATH)) ssh = SSHManager() pack_path = '/var/www/nailgun/fuel-ostf/' full_pack_path = os.path.join(pack_path, 'fuel-ostf*.noarch.rpm') ssh.upload_to_remote(ssh.admin_ip, source=settings.UPDATE_FUEL_PATH.rstrip('/'), target=pack_path) # Check old fuel-ostf package cmd = "rpm -q fuel-ostf" old_package = ssh.execute_on_remote(ssh.admin_ip, cmd=cmd)['stdout_str'] logger.info('Current package version of ' 'fuel-ostf: {0}'.format(old_package)) cmd = "rpm -qp {0}".format(full_pack_path) new_package = ssh.execute_on_remote(ssh.admin_ip, cmd=cmd)['stdout_str'] logger.info('Package from review {0}'.format(new_package)) if old_package == new_package: logger.info('Package {0} is installed'.format(new_package)) return cmd = "service ostf stop" ssh.execute_on_remote(ssh.admin_ip, cmd=cmd) cmd = "service ostf status" helpers.wait(lambda: "dead" in ssh.execute_on_remote( ssh.admin_ip, cmd=cmd, raise_on_assert=False, assert_ec_equal=[3])[ 'stdout_str'], timeout=60) logger.info("OSTF status: inactive") cmd = "rpm -e fuel-ostf" ssh.execute_on_remote(ssh.admin_ip, cmd=cmd) cmd = "rpm -Uvh --oldpackage {0}".format(full_pack_path) ssh.execute_on_remote(ssh.admin_ip, cmd=cmd) cmd = "rpm -q fuel-ostf" installed_package = ssh.execute_on_remote(ssh.admin_ip, cmd=cmd)['stdout_str'] assert_equal( installed_package, new_package, "The new package {0} was not installed. Actual {1}".format( new_package, installed_package)) cmd = "service ostf start" ssh.execute_on_remote(ssh.admin_ip, cmd=cmd) cmd = "service ostf status" helpers.wait(lambda: "running" in ssh.execute_on_remote( ssh.admin_ip, cmd=cmd)['stdout_str'], timeout=60) cmd = "curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:8777" helpers.wait(lambda: "401" in ssh.execute_on_remote( ssh.admin_ip, cmd=cmd, raise_on_assert=False)['stdout_str'], timeout=60) logger.info("OSTF status: RUNNING")
def centos_setup_fuel(self, hostname): logger.info("upload fuel-release packet") if not settings.FUEL_RELEASE_PATH: raise exceptions.FuelQAVariableNotSet('FUEL_RELEASE_PATH', '/path') try: ssh = SSHManager() pack_path = '/tmp/' full_pack_path = os.path.join(pack_path, 'fuel-release*.noarch.rpm') ssh.upload_to_remote(ip=ssh.admin_ip, source=settings.FUEL_RELEASE_PATH.rstrip('/'), target=pack_path) except Exception: logger.exception("Could not upload package") logger.debug("Update host information") cmd = "echo HOSTNAME={} >> /etc/sysconfig/network".format(hostname) ssh.execute_on_remote(ssh.admin_ip, cmd=cmd) cmd = "echo {0} {1} {2} >> /etc/hosts".format( ssh.admin_ip, hostname, settings.FUEL_MASTER_HOSTNAME) ssh.execute_on_remote(ssh.admin_ip, cmd=cmd) cmd = "hostname {}".format(hostname) ssh.execute_on_remote(ssh.admin_ip, cmd=cmd) logger.debug("setup MOS repositories") cmd = "rpm -ivh {}".format(full_pack_path) ssh.execute_on_remote(ssh.admin_ip, cmd=cmd) cmd = "yum install -y fuel-setup" ssh.execute_on_remote(ssh.admin_ip, cmd=cmd) cmd = "yum install -y screen" ssh.execute_on_remote(ssh.admin_ip, cmd=cmd) logger.info("Install Fuel services") cmd = "screen -dm bash -c 'showmenu=no wait_for_external_config=yes " \ "bootstrap_admin_node.sh'" ssh.execute_on_remote(ssh.admin_ip, cmd=cmd) self.env.wait_for_external_config() self.env.admin_actions.modify_configs(self.env.d_env.router()) self.env.kill_wait_for_external_config() self.env.wait_bootstrap() logger.debug("Check Fuel services") self.env.admin_actions.wait_for_fuel_ready() logger.debug("post-installation configuration of Fuel services") self.fuel_post_install_actions()
def patch_and_assemble_ubuntu_bootstrap(environment): """Replaced initramfs.img in /var/www/nailgun/ with newly_builded from review environment - Environment Model object - self.env """ logger.info("Update fuel-agent code and assemble new ubuntu bootstrap") ssh = SSHManager() if not settings.UPDATE_FUEL: raise Exception("{} variable don't exist" .format(settings.UPDATE_FUEL)) try: pack_path = '/var/www/nailgun/fuel-agent-review/' ssh.upload_to_remote( ip=ssh.admin_ip, source=settings.FUEL_AGENT_REPO_PATH.rstrip('/'), target=pack_path) # renew code in bootstrap # Step 1 - install squashfs-tools cmd = "yum install -y squashfs-tools" ssh.execute_on_remote(ip=ssh.admin_ip, cmd=cmd) # Step 2 - unpack bootstrap bootstrap = "/var/www/nailgun/bootstraps/active_bootstrap" bootstrap_var = "/var/root.squashfs" cmd = "unsquashfs -d /var/root.squashfs {}/root.squashfs".format( bootstrap) ssh.execute_on_remote(ip=ssh.admin_ip, cmd=cmd) # Step 3 - replace fuel-agent code in unpacked bootstrap agent_path = "/usr/lib/python2.7/dist-packages/fuel_agent" bootstrap_file = bootstrap + "/root.squashfs" cmd = ("rsync -r {2}fuel_agent/* {0}{1}/;" "mv {3} /var/root.squashfs.old;" ).format(bootstrap_var, agent_path, pack_path, bootstrap_file) ssh.execute_on_remote(ip=ssh.admin_ip, cmd=cmd) # Step 4 - assemble new bootstrap compression = "-comp xz" no_progress_bar = "-no-progress" no_append = "-noappend" image_rebuild = "mksquashfs {0} {1} {2} {3} {4}".format( bootstrap_var, bootstrap_file, compression, no_progress_bar, no_append) ssh.execute_on_remote(ip=ssh.admin_ip, cmd=image_rebuild) with environment.d_env.get_admin_remote() as remote: checkers.check_file_exists(remote, '{0}'.format(bootstrap_file)) except Exception as e: logger.error("Could not upload package {e}".format(e=e)) raise
def check_package_version_injected_in_bootstraps(package, cluster_id=None, ironic=None): ssh = SSHManager() try: pack_path = '/var/www/nailgun/{}/'.format(package) ssh.upload_to_remote(ip=ssh.admin_ip, source=settings.UPDATE_FUEL_PATH.rstrip('/'), target=pack_path) except Exception: logger.exception("Could not upload package") raise # Step 1 - unpack active bootstrap logger.info("unpack active bootstrap") if ironic: bootstrap = "/var/www/nailgun/bootstrap/ironic/{}".format(cluster_id) else: bootstrap = "/var/www/nailgun/bootstraps/active_bootstrap" bootstrap_var = "/var/root.squashfs" cmd = "unsquashfs -d {} {}/root.squashfs".format(bootstrap_var, bootstrap) ssh.execute_on_remote(ip=ssh.admin_ip, cmd=cmd) # Step 2 - check package version logger.info("check package {} version injected in ubuntu bootstrap".format( package)) cmd = "ls {}|grep {} |grep deb |cut -f 2 -d '_'".format(pack_path, package) package_from_review = ssh.execute_on_remote(ip=ssh.admin_ip, cmd=cmd)['stdout_str'] logger.info("package from review is {}".format(package_from_review)) awk_pattern = "awk '{print $2}'" cmd = "chroot {}/ /bin/bash -c \"dpkg -s {}\"|grep Version|{}".format( bootstrap_var, package, awk_pattern) installed_package = ssh.execute_on_remote(ip=ssh.admin_ip, cmd=cmd)['stdout_str'] logger.info("injected package is {}".format(installed_package)) assert_equal( installed_package, package_from_review, "The new package {0} wasn't injected in bootstrap".format( package_from_review)) # Step 3 - remove unpacked bootstrap cmd = "rm -rf {}".format(bootstrap_var) ssh.execute_on_remote(ip=ssh.admin_ip, cmd=cmd)
def upload_nailgun_agent_rpm(): """Upload nailgun_agent.rpm on master node """ ssh = SSHManager() logger.info("Upload nailgun-agent") if not settings.UPDATE_FUEL: raise exceptions.FuelQAVariableNotSet('UPDATE_FUEL', 'True') pack_path = '/var/www/nailgun/nailgun-agent-review/' ssh.upload_to_remote(ip=ssh.admin_ip, source=settings.UPDATE_FUEL_PATH.rstrip('/'), target=pack_path) # Extract rpm context cmd = 'cd {0}; rpm2cpio {1} | cpio -idmv'.format( pack_path, 'nailgun-agent-*.noarch.rpm ') ssh.execute_on_remote(ssh.admin_ip, cmd)
def patch_and_assemble_ubuntu_bootstrap(environment): """Replaced initramfs.img in /var/www/nailgun/ with newly_builded from review environment - Environment Model object - self.env """ logger.info("Update fuel-agent code and assemble new ubuntu bootstrap") ssh = SSHManager() if not settings.UPDATE_FUEL: raise Exception("{} variable don't exist".format(settings.UPDATE_FUEL)) try: pack_path = '/var/www/nailgun/fuel-agent-review/' ssh.upload_to_remote(ip=ssh.admin_ip, source=settings.FUEL_AGENT_REPO_PATH.rstrip('/'), target=pack_path) # renew code in bootstrap # Step 1 - install squashfs-tools cmd = "yum install -y squashfs-tools" ssh.execute_on_remote(ip=ssh.admin_ip, cmd=cmd) # Step 2 - unpack bootstrap bootstrap = "/var/www/nailgun/bootstraps/active_bootstrap" bootstrap_var = "/var/root.squashfs" cmd = "unsquashfs -d /var/root.squashfs {}/root.squashfs".format( bootstrap) ssh.execute_on_remote(ip=ssh.admin_ip, cmd=cmd) # Step 3 - replace fuel-agent code in unpacked bootstrap agent_path = "/usr/lib/python2.7/dist-packages/fuel_agent" bootstrap_file = bootstrap + "/root.squashfs" cmd = ("rsync -r {2}fuel_agent/* {0}{1}/;" "mv {3} /var/root.squashfs.old;").format( bootstrap_var, agent_path, pack_path, bootstrap_file) ssh.execute_on_remote(ip=ssh.admin_ip, cmd=cmd) # Step 4 - assemble new bootstrap compression = "-comp xz" no_progress_bar = "-no-progress" no_append = "-noappend" image_rebuild = "mksquashfs {0} {1} {2} {3} {4}".format( bootstrap_var, bootstrap_file, compression, no_progress_bar, no_append) ssh.execute_on_remote(ip=ssh.admin_ip, cmd=image_rebuild) checkers.check_file_exists(ssh.admin_ip, '{0}'.format(bootstrap_file)) except Exception as e: logger.error("Could not upload package {e}".format(e=e)) raise
def upload_nailgun_agent_rpm(): """Upload nailgun_agent.rpm on master node """ ssh = SSHManager() logger.info("Upload nailgun-agent") if not settings.UPDATE_FUEL: raise exceptions.FuelQAVariableNotSet('UPDATE_FUEL', 'True') pack_path = '/var/www/nailgun/nailgun-agent-review/' ssh.upload_to_remote( ip=ssh.admin_ip, source=settings.UPDATE_FUEL_PATH.rstrip('/'), target=pack_path) # Extract rpm context cmd = 'cd {0}; rpm2cpio {1} | cpio -idmv'.format( pack_path, 'nailgun-agent-*.noarch.rpm ') ssh.execute_on_remote(ssh.admin_ip, cmd)
def patch_centos_bootstrap(): """Replaced initramfs.img in /var/www/nailgun/ with newly_builded from review environment - Environment Model object - self.env """ logger.info("Update fuel-agent code and assemble new bootstrap") ssh = SSHManager() if not settings.UPDATE_FUEL: raise Exception("{} variable don't exist" .format(settings.UPDATE_FUEL)) try: pack_path = '/var/www/nailgun/fuel-agent-review/' ssh.upload_to_remote( ip=ssh.admin_ip, source=settings.FUEL_AGENT_REPO_PATH.rstrip('/'), target=pack_path) # Step 1 - unpack bootstrap bootstrap_var = "/var/initramfs" bootstrap = "/var/www/nailgun/bootstrap" cmd = ("mkdir {0}; cp /{1}/initramfs.img {0}/; cd {0}; " "cat initramfs.img | gunzip | cpio -imudv;").format( bootstrap_var, bootstrap) result = ssh.execute_on_remote( ip=ssh.admin_ip, cmd=cmd)['stdout_str'] logger.debug("Patching bootsrap finishes with {0}".format(result)) # Step 2 - replace fuel-agent code in unpacked bootstrap agent_path = "/usr/lib/python2.7/site-packages/fuel_agent" image_rebuild = "{} | {} | {}".format( "find . -xdev", "cpio --create --format='newc'", "gzip -9 > /var/initramfs.img.updated") cmd = ("rm -rf {0}/initramfs.img; " "rsync -r {2}fuel_agent/* {0}{1}/;" "cd {0}/;" "{3};").format(bootstrap_var, agent_path, pack_path, image_rebuild) result = ssh.execute_on_remote( ip=ssh.admin_ip, cmd=cmd)['stdout_str'] logger.debug("Failed to rebuild image with {0}".format(result)) except Exception as e: logger.error("Could not upload package {e}".format(e=e)) raise
def install_mos_repos(): """ Upload and install fuel-release packet with mos-repo description and install necessary packets for packetary Fuel installation :return: nothing """ logger.info("upload fuel-release packet") if not settings.FUEL_RELEASE_PATH: raise exceptions.FuelQAVariableNotSet('FUEL_RELEASE_PATH', '/path') try: ssh = SSHManager() pack_path = '/tmp/' full_pack_path = os.path.join(pack_path, 'fuel-release*.noarch.rpm') ssh.upload_to_remote( ip=ssh.admin_ip, source=settings.FUEL_RELEASE_PATH.rstrip('/'), target=pack_path) if settings.RPM_REPOS_YAML: with ssh.open_on_remote( ip=ssh.admin_ip, path='/etc/yum.repos.d/custom.repo', mode="w") as f: f.write(generate_yum_repos_config(settings.RPM_REPOS_YAML)) if settings.DEB_REPOS_YAML: ssh = SSHManager() pack_path = "/root/default_deb_repos.yaml" ssh.upload_to_remote( ip=ssh.admin_ip, source=settings.DEB_REPOS_YAML, target=pack_path) except Exception: logger.exception("Could not upload package") raise logger.debug("setup MOS repositories") cmd = "rpm -ivh {}".format(full_pack_path) ssh.execute_on_remote(ssh.admin_ip, cmd=cmd) cmd = "yum install -y fuel-setup" ssh.execute_on_remote(ssh.admin_ip, cmd=cmd)
def replace_fuel_agent_rpm(): """Replaced fuel_agent.rpm on master node with fuel_agent.rpm from review """ ssh = SSHManager() logger.info("Patching fuel-agent") if not settings.UPDATE_FUEL: raise exceptions.FuelQAVariableNotSet('UPDATE_FUEL', 'True') try: pack_path = '/var/www/nailgun/fuel-agent/' full_pack_path = os.path.join(pack_path, 'fuel-agent*.noarch.rpm') ssh.upload_to_remote( ip=ssh.admin_ip, source=settings.UPDATE_FUEL_PATH.rstrip('/'), target=pack_path) # Update fuel-agent on master node cmd = "rpm -q fuel-agent" old_package = ssh.execute_on_remote(ssh.admin_ip, cmd)['stdout_str'] cmd = "rpm -qp {0}".format(full_pack_path) new_package = ssh.execute_on_remote(ssh.admin_ip, cmd)['stdout_str'] logger.info("Updating package {0} with {1}" .format(old_package, new_package)) if old_package != new_package: logger.info("Updating fuel-agent package on master node") logger.info('Try to install package {0}'.format( new_package)) cmd = "rpm -Uvh --oldpackage {0}".format(full_pack_path) ssh.execute_on_remote(ssh.admin_ip, cmd) cmd = "rpm -q fuel-agent" installed_package = ssh.execute_on_remote( ssh.admin_ip, cmd)['stdout_str'] assert_equal(installed_package, new_package, "The new package {0} was not installed". format(new_package)) except Exception as e: logger.error("Could not upload package {e}".format(e=e)) raise
def replace_fuel_agent_rpm(): """Replaced fuel_agent.rpm on master node with fuel_agent.rpm from review """ ssh = SSHManager() logger.info("Patching fuel-agent") if not settings.UPDATE_FUEL: raise exceptions.FuelQAVariableNotSet('UPDATE_FUEL', 'True') try: pack_path = '/var/www/nailgun/fuel-agent/' full_pack_path = os.path.join(pack_path, 'fuel-agent*.noarch.rpm') ssh.upload_to_remote(ip=ssh.admin_ip, source=settings.UPDATE_FUEL_PATH.rstrip('/'), target=pack_path) # Update fuel-agent on master node cmd = "rpm -q fuel-agent" old_package = ssh.execute_on_remote(ssh.admin_ip, cmd)['stdout_str'] cmd = "rpm -qp {0}".format(full_pack_path) new_package = ssh.execute_on_remote(ssh.admin_ip, cmd)['stdout_str'] logger.info("Updating package {0} with {1}".format( old_package, new_package)) if old_package != new_package: logger.info("Updating fuel-agent package on master node") logger.info('Try to install package {0}'.format(new_package)) cmd = "rpm -Uvh --oldpackage {0}".format(full_pack_path) ssh.execute_on_remote(ssh.admin_ip, cmd) cmd = "rpm -q fuel-agent" installed_package = ssh.execute_on_remote(ssh.admin_ip, cmd)['stdout_str'] assert_equal( installed_package, new_package, "The new package {0} was not installed".format(new_package)) except Exception as e: logger.error("Could not upload package {e}".format(e=e)) raise
class BaseActions(object): """BaseActions.""" # TODO documentation def __init__(self): self.ssh_manager = SSHManager() self.admin_ip = self.ssh_manager.admin_ip def __repr__(self): klass, obj_id = type(self), hex(id(self)) return "[{klass}({obj_id})]".format(klass=klass, obj_id=obj_id) def restart_service(self, service): result = self.ssh_manager.execute( ip=self.admin_ip, cmd="systemctl restart {0}".format(service)) return result['exit_code'] == 0 @staticmethod def put_value_to_local_yaml(old_file, new_file, element, value): """Changes content in old_file at element is given to the new value and creates new file with changed content :param old_file: a path to the file content from to be changed :param new_file: a path to the new file to ve created with new content :param element: tuple with path to element to be changed for example: ['root_elem', 'first_elem', 'target_elem'] if there are a few elements with equal names use integer to identify which element should be used :return: nothing """ with open(old_file, 'r') as f_old: yaml_dict = yaml.load(f_old) origin_yaml = yaml_dict for k in element[:-1]: yaml_dict = yaml_dict[k] yaml_dict[element[-1]] = value with open(new_file, 'w') as f_new: yaml.dump(origin_yaml, f_new, default_flow_style=False, default_style='"') @staticmethod def get_value_from_local_yaml(yaml_file, element): """Get a value of the element from the local yaml file :param str yaml_file: a path to the yaml file :param list element: list with path to element to be read for example: ['root_elem', 'first_elem', 'target_elem'] if there are a few elements with equal names use integer to identify which element should be used :return obj: value """ with open(yaml_file, 'r') as f_old: yaml_dict = yaml.load(f_old) for i, k in enumerate(element): try: yaml_dict = yaml_dict[k] except IndexError: raise IndexError( "Element {0} not found in the file {1}".format( element[:i + 1], f_old)) except KeyError: raise KeyError("Element {0} not found in the file {1}".format( element[:i + 1], f_old)) return yaml_dict def change_remote_yaml(self, path_to_file, element, value): """Changes values in the yaml file stored There is no need to copy file manually :param path_to_file: absolute path to the file :param element: list with path to the element be changed :param value: new value for element :return: Nothing """ old_file = '/tmp/temp_file_{0}.old.yaml'.format(str(os.getpid())) new_file = '/tmp/temp_file_{0}.new.yaml'.format(str(os.getpid())) self.ssh_manager.download_from_remote(ip=self.admin_ip, destination=path_to_file, target=old_file) self.put_value_to_local_yaml(old_file, new_file, element, value) self.ssh_manager.upload_to_remote(ip=self.admin_ip, source=new_file, target=path_to_file) os.remove(old_file) os.remove(new_file) def get_value_from_remote_yaml(self, path_to_file, element): """Get a value from the yaml file stored on the master node :param str path_to_file: absolute path to the file :param list element: list with path to the element :return obj: value """ host_tmp_file = '/tmp/temp_file_{0}.yaml'.format(str(os.getpid())) self.ssh_manager.download_from_remote(ip=self.admin_ip, destination=path_to_file, target=host_tmp_file) value = self.get_value_from_local_yaml(host_tmp_file, element) os.remove(host_tmp_file) return value def put_value_to_remote_yaml(self, path_to_file, element, value): """Put a value to the yaml file stored on the master node :param str path_to_file: absolute path to the file :param list element: list with path to the element be changed :param value: new value for element :return: None """ host_tmp_file = '/tmp/temp_file_{0}.yaml'.format(str(os.getpid())) self.ssh_manager.download_from_remote(ip=self.admin_ip, destination=path_to_file, target=host_tmp_file) self.put_value_to_local_yaml(host_tmp_file, host_tmp_file, element, value) self.ssh_manager.upload_to_remote(ip=self.admin_ip, source=host_tmp_file, target=path_to_file) os.remove(host_tmp_file)
class BaseActions(object): """BaseActions.""" # TODO documentation def __init__(self): self.ssh_manager = SSHManager() self.admin_ip = self.ssh_manager.admin_ip def __repr__(self): klass, obj_id = type(self), hex(id(self)) return "[{klass}({obj_id})]".format(klass=klass, obj_id=obj_id) # TODO(kozhukalov): This method seems not needed and # can easily be replaced by using execute_on_remote # available in SSHManager (up to the type of return value) def execute(self, cmd, exit_code=None, stdin=None): if stdin is not None: cmd = 'echo "{0}" | {1}'.format(stdin, cmd) result = self.ssh_manager.execute(ip=self.admin_ip, cmd=cmd) if exit_code is not None: assert_equal(exit_code, result['exit_code'], ('Command {cmd} returned exit code "{e}", but ' 'expected "{c}". Output: {out}; {err} ').format( cmd=cmd, e=result['exit_code'], c=exit_code, out=result['stdout'], err=result['stderr'])) return ''.join(result['stdout']).strip() def restart_service(self, service): result = self.ssh_manager(ip=self.admin_ip, cmd="systemctl restart {0}".format(service)) return result['exit_code'] == 0 def put_value_to_local_yaml(self, old_file, new_file, element, value): """Changes content in old_file at element is given to the new value and creates new file with changed content :param old_file: a path to the file content from to be changed :param new_file: a path to the new file to ve created with new content :param element: tuple with path to element to be changed for example: ['root_elem', 'first_elem', 'target_elem'] if there are a few elements with equal names use integer to identify which element should be used :return: nothing """ with open(old_file, 'r') as f_old: yaml_dict = yaml.load(f_old) origin_yaml = yaml_dict for k in element[:-1]: yaml_dict = yaml_dict[k] yaml_dict[element[-1]] = value with open(new_file, 'w') as f_new: yaml.dump(origin_yaml, f_new, default_flow_style=False, default_style='"') def get_value_from_local_yaml(self, yaml_file, element): """Get a value of the element from the local yaml file :param str yaml_file: a path to the yaml file :param list element: list with path to element to be read for example: ['root_elem', 'first_elem', 'target_elem'] if there are a few elements with equal names use integer to identify which element should be used :return obj: value """ with open(yaml_file, 'r') as f_old: yaml_dict = yaml.load(f_old) for i, k in enumerate(element): try: yaml_dict = yaml_dict[k] except IndexError: raise IndexError( "Element {0} not found in the file {1}".format( element[:i + 1], f_old)) except KeyError: raise KeyError("Element {0} not found in the file {1}".format( element[:i + 1], f_old)) return yaml_dict def change_remote_yaml(self, path_to_file, element, value): """Changes values in the yaml file stored There is no need to copy file manually :param path_to_file: absolute path to the file :param element: list with path to the element be changed :param value: new value for element :return: Nothing """ old_file = '/tmp/temp_file_{0}.old.yaml'.format(str(os.getpid())) new_file = '/tmp/temp_file_{0}.new.yaml'.format(str(os.getpid())) self.ssh_manager.download_from_remote(ip=self.admin_ip, destination=path_to_file, target=old_file) self.put_value_to_local_yaml(old_file, new_file, element, value) self.ssh_manager.upload_to_remote(ip=self.admin_ip, source=new_file, target=path_to_file) os.remove(old_file) os.remove(new_file) def get_value_from_remote_yaml(self, path_to_file, element): """Get a value from the yaml file stored on the master node :param str path_to_file: absolute path to the file :param list element: list with path to the element :return obj: value """ host_tmp_file = '/tmp/temp_file_{0}.yaml'.format(str(os.getpid())) self.ssh_manager.download_from_remote(ip=self.admin_ip, destination=path_to_file, target=host_tmp_file) value = self.get_value_from_local_yaml(host_tmp_file, element) os.remove(host_tmp_file) return value def put_value_to_remote_yaml(self, path_to_file, element, value): """Put a value to the yaml file stored on the master node :param str path_to_file: absolute path to the file :param list element: list with path to the element be changed :param value: new value for element :return: None """ host_tmp_file = '/tmp/temp_file_{0}.yaml'.format(str(os.getpid())) self.ssh_manager.download_from_remote(ip=self.admin_ip, destination=path_to_file, target=host_tmp_file) self.put_value_to_local_yaml(host_tmp_file, host_tmp_file, element, value) self.ssh_manager.upload_to_remote(ip=self.admin_ip, source=host_tmp_file, target=path_to_file) os.remove(host_tmp_file)
class CustomRepo(object): """CustomRepo.""" # TODO documentation def __init__(self): self.ssh_manager = SSHManager() self.ip = self.ssh_manager.admin_ip self.path_scripts = ('{0}/fuelweb_test/helpers/' .format(os.environ.get("WORKSPACE", "./"))) self.remote_path_scripts = '/tmp/' self.ubuntu_script = 'regenerate_ubuntu_repo' self.centos_script = 'regenerate_centos_repo' self.local_mirror_ubuntu = settings.LOCAL_MIRROR_UBUNTU self.local_mirror_centos = settings.LOCAL_MIRROR_CENTOS self.ubuntu_release = settings.UBUNTU_RELEASE self.centos_supported_archs = ['noarch', 'x86_64'] self.pkgs_list = [] self.custom_pkgs_mirror_path = '' if settings.OPENSTACK_RELEASE_UBUNTU in settings.OPENSTACK_RELEASE: # Trying to determine the root of Ubuntu repository pkgs_path = settings.CUSTOM_PKGS_MIRROR.split('/dists/') if len(pkgs_path) == 2: self.custom_pkgs_mirror = pkgs_path[0] self.custom_pkgs_mirror_path = '/dists/{}'.format(pkgs_path[1]) else: self.custom_pkgs_mirror = settings.CUSTOM_PKGS_MIRROR else: self.custom_pkgs_mirror = settings.CUSTOM_PKGS_MIRROR def prepare_repository(self): """Prepare admin node to packages testing Scenario: 1. Temporary set nameserver to local router on admin node 2. Install tools to manage rpm/deb repository 3. Retrieve list of packages from custom repository 4. Download packages to local rpm/deb repository 5. Update .yaml file with new packages version 6. Re-generate repo using shell scripts on admin node """ # Check necessary settings and revert a snapshot if not self.custom_pkgs_mirror: return logger.info("Custom mirror with new packages: {0}" .format(settings.CUSTOM_PKGS_MIRROR)) if settings.OPENSTACK_RELEASE_UBUNTU in settings.OPENSTACK_RELEASE: # Ubuntu master_tools = ['dpkg', 'dpkg-devel', 'dpkg-dev'] self.install_tools(master_tools) self.get_pkgs_list_ubuntu() pkgs_local_path = ('{0}/pool/' .format(self.local_mirror_ubuntu)) self.download_pkgs(pkgs_local_path) self.regenerate_repo(self.ubuntu_script, self.local_mirror_ubuntu) else: # CentOS master_tools = ['createrepo'] self.install_tools(master_tools) self.get_pkgs_list_centos() pkgs_local_path = '{0}/Packages/'.format(self.local_mirror_centos) self.download_pkgs(pkgs_local_path) self.regenerate_repo(self.centos_script, self.local_mirror_centos) # Install tools to masternode def install_tools(self, master_tools=None): if master_tools is None: master_tools = [] logger.info("Installing necessary tools for {0}" .format(settings.OPENSTACK_RELEASE)) for master_tool in master_tools: exit_code = install_pkg_2( ip=self.ip, pkg_name=master_tool ) assert_equal(0, exit_code, 'Cannot install package {0} ' 'on admin node.'.format(master_tool)) # Ubuntu: Creating list of packages from the additional mirror def get_pkgs_list_ubuntu(self): url = "{0}/{1}/Packages".format(self.custom_pkgs_mirror, self.custom_pkgs_mirror_path) logger.info("Retrieving additional packages from the custom mirror:" " {0}".format(url)) try: pkgs_release = urllib2.urlopen(url).read() except (urllib2.HTTPError, urllib2.URLError): logger.error(traceback.format_exc()) url_gz = '{0}.gz'.format(url) logger.info( "Retrieving additional packages from the custom mirror:" " {0}".format(url_gz)) try: pkgs_release_gz = urllib2.urlopen(url_gz).read() except (urllib2.HTTPError, urllib2.URLError): logger.error(traceback.format_exc()) raise try: d = zlib.decompressobj(zlib.MAX_WBITS | 32) pkgs_release = d.decompress(pkgs_release_gz) except Exception: logger.error('Ubuntu mirror error: Could not decompress {0}\n' '{1}'.format(url_gz, traceback.format_exc())) raise packages = (pkg for pkg in pkgs_release.split("\n\n") if pkg) for package in packages: upkg = {pstr.split()[0].lower(): ''.join(pstr.split()[1:]) for pstr in package.split("\n") if pstr[0].strip()} upkg_keys = ["package:", "version:", "filename:"] assert_equal(True, all(x in upkg for x in upkg_keys), 'Missing one of the statements ["Package:", ' '"Version:", "Filename:"] in {0}'.format(url)) # TODO: add dependencies list to upkg self.pkgs_list.append(upkg) # Centos: Creating list of packages from the additional mirror def get_pkgs_list_centos(self): logger.info("Retrieving additional packages from the custom mirror:" " {0}".format(self.custom_pkgs_mirror)) url = "{0}/repodata/repomd.xml".format(self.custom_pkgs_mirror) try: repomd_data = urllib2.urlopen(url).read() except (urllib2.HTTPError, urllib2.URLError): logger.error(traceback.format_exc()) raise # Remove namespace attribute before parsing XML repomd_data = re.sub(' xmlns="[^"]+"', '', repomd_data, count=1) tree_repomd_data = ElementTree.fromstring(repomd_data) lists_location = '' for repomd in tree_repomd_data.findall('data'): if repomd.get('type') == 'primary': repomd_location = repomd.find('location') lists_location = repomd_location.get('href') assert_equal(True, lists_location is not '', 'CentOS mirror error:' ' Could not parse {0}\nlists_location = "{1}"\n{2}' .format(url, lists_location, traceback.format_exc())) url = "{0}/{1}".format(self.custom_pkgs_mirror, lists_location) try: lists_data = urllib2.urlopen(url).read() except (urllib2.HTTPError, urllib2.URLError): logger.error(traceback.format_exc()) raise if '.xml.gz' in lists_location: try: d = zlib.decompressobj(zlib.MAX_WBITS | 32) lists_data = d.decompress(lists_data) except Exception: logger.error('CentOS mirror error: Could not decompress {0}\n' '{1}'.format(url, traceback.format_exc())) raise # Remove namespace attribute before parsing XML lists_data = re.sub(' xmlns="[^"]+"', '', lists_data, count=1) tree_lists_data = ElementTree.fromstring(lists_data) for flist in tree_lists_data.findall('package'): if flist.get('type') == 'rpm': flist_arch = flist.find('arch').text if flist_arch in self.centos_supported_archs: flist_name = flist.find('name').text flist_location = flist.find('location') flist_file = flist_location.get('href') flist_version = flist.find('version') flist_ver = '{0}-{1}'.format(flist_version.get('ver'), flist_version.get('rel')) cpkg = {'package:': flist_name, 'version:': flist_ver, 'filename:': flist_file} # TODO: add dependencies list to cpkg self.pkgs_list.append(cpkg) # Download packages (local_folder) def download_pkgs(self, pkgs_local_path): # Process the packages list: total_pkgs = len(self.pkgs_list) logger.info('Found {0} custom package(s)'.format(total_pkgs)) for npkg, pkg in enumerate(self.pkgs_list): # TODO: Previous versions of the updating packages must be removed # to avoid unwanted packet manager dependencies resolution # (when some package still depends on other package which # is not going to be installed) logger.info('({0}/{1}) Downloading package: {2}/{3}' .format(npkg + 1, total_pkgs, self.custom_pkgs_mirror, pkg["filename:"])) pkg_ext = pkg["filename:"].split('.')[-1] if pkg_ext == 'deb': path_suff = 'main/' elif pkg_ext == 'udeb': path_suff = 'debian-installer/' else: path_suff = '' wget_cmd = "wget --no-verbose --directory-prefix {0} {1}/{2}"\ .format(pkgs_local_path + path_suff, self.custom_pkgs_mirror, pkg["filename:"]) wget_result = self.ssh_manager.execute( ip=self.ip, cmd=wget_cmd ) assert_equal(0, wget_result['exit_code'], self.assert_msg(wget_cmd, wget_result['stderr'])) # Upload regenerate* script to masternode (script name) def regenerate_repo(self, regenerate_script, local_mirror_path): # Uploading scripts that prepare local repositories: # 'regenerate_centos_repo' and 'regenerate_ubuntu_repo' try: self.ssh_manager.upload_to_remote( ip=self.ip, source='{0}/{1}'.format(self.path_scripts, regenerate_script), target=self.remote_path_scripts ) self.ssh_manager.execute_on_remote( ip=self.ip, cmd='chmod 755 {0}/{1}'.format(self.remote_path_scripts, regenerate_script) ) except Exception: logger.error('Could not upload scripts for updating repositories.' '\n{0}'.format(traceback.format_exc())) raise # Update the local repository using previously uploaded script. script_cmd = '{0}/{1} {2} {3}'.format(self.remote_path_scripts, regenerate_script, local_mirror_path, self.ubuntu_release) script_result = self.ssh_manager.execute( ip=self.ip, cmd=script_cmd ) assert_equal(0, script_result['exit_code'], self.assert_msg(script_cmd, script_result['stderr'])) logger.info('Local repository {0} has been updated successfully.' .format(local_mirror_path)) def assert_msg(self, cmd, err): return 'Executing \'{0}\' on the admin node has failed with: {1}'\ .format(cmd, err) def check_puppet_logs(self): logger.info("Check puppet logs for packages with unmet dependencies.") if settings.OPENSTACK_RELEASE_UBUNTU in settings.OPENSTACK_RELEASE: err_deps = self.check_puppet_logs_ubuntu() else: err_deps = self.check_puppet_logs_centos() for err_deps_key in err_deps.keys(): logger.info('Error: Package: {0} has unmet dependencies:' .format(err_deps_key)) for dep in err_deps[err_deps_key]: logger.info(' {0}'.format(dep.strip())) logger.info("Check puppet logs completed.") def check_puppet_logs_ubuntu(self): """ Check puppet-agent.log files on all nodes for package dependency errors during a cluster deployment (ubuntu)""" err_start = 'The following packages have unmet dependencies:' err_end = ('Unable to correct problems,' ' you have held broken packages.') cmd = ('fgrep -h -e " Depends: " -e "{0}" -e "{1}" ' '/var/log/docker-logs/remote/node-*/' 'puppet*.log'.format(err_start, err_end)) result = self.ssh_manager.execute( ip=self.ip, cmd=cmd )['stdout'] err_deps = {} err_deps_key = '' err_deps_flag = False # Forming a dictionary of package names # with sets of required packages. for res_str in result: if err_deps_flag: if err_end in res_str: err_deps_flag = False elif ": Depends:" in res_str: str0, str1, str2 = res_str.partition(': Depends:') err_deps_key = ''.join(str0.split()[-1:]) if err_deps_key not in err_deps: err_deps[err_deps_key] = set() if 'but it is not' in str2 or 'is to be installed' in str2: err_deps[err_deps_key].add('Depends:{0}' .format(str2)) elif 'Depends:' in res_str and err_deps_key: str0, str1, str2 = res_str.partition('Depends:') if 'but it is not' in str2 or 'is to be installed' in str2: err_deps[err_deps_key].add(str1 + str2) else: err_deps_key = '' elif err_start in res_str: err_deps_flag = True return err_deps def check_puppet_logs_centos(self): """ Check puppet-agent.log files on all nodes for package dependency errors during a cluster deployment (centos)""" cmd = ('fgrep -h -e "Error: Package: " -e " Requires: " /var/log/' 'docker-logs/remote/node-*/puppet*.log') result = self.ssh_manager.execute( ip=self.ip, cmd=cmd )['stdout'] err_deps = {} err_deps_key = '' # Forming a dictionary of package names # with sets of required packages. for res_str in result: if 'Error: Package:' in res_str: err_deps_key = res_str.partition('Error: Package: ')[2] if err_deps_key not in err_deps: err_deps[err_deps_key] = set() elif ' Requires: ' in res_str and err_deps_key: str0, str1, str2 = res_str.partition(' Requires: ') err_deps[err_deps_key].add(str1 + str2) else: err_deps_key = '' return err_deps
class BaseActions(object): """BaseActions.""" # TODO documentation def __init__(self): self.ssh_manager = SSHManager() self.admin_ip = self.ssh_manager.admin_ip def __repr__(self): klass, obj_id = type(self), hex(id(self)) return "[{klass}({obj_id})]".format( klass=klass, obj_id=obj_id) def restart_service(self, service): result = self.ssh_manager.execute( ip=self.admin_ip, cmd="systemctl restart {0}".format(service)) return result['exit_code'] == 0 @staticmethod def put_value_to_local_yaml(old_file, new_file, element, value): """Changes content in old_file at element is given to the new value and creates new file with changed content :param old_file: a path to the file content from to be changed :param new_file: a path to the new file to ve created with new content :param element: tuple with path to element to be changed for example: ['root_elem', 'first_elem', 'target_elem'] if there are a few elements with equal names use integer to identify which element should be used :return: nothing """ with open(old_file, 'r') as f_old: yaml_dict = yaml.load(f_old) origin_yaml = yaml_dict for k in element[:-1]: yaml_dict = yaml_dict[k] yaml_dict[element[-1]] = value with open(new_file, 'w') as f_new: yaml.dump(origin_yaml, f_new, default_flow_style=False, default_style='"') @staticmethod def get_value_from_local_yaml(yaml_file, element): """Get a value of the element from the local yaml file :param str yaml_file: a path to the yaml file :param list element: list with path to element to be read for example: ['root_elem', 'first_elem', 'target_elem'] if there are a few elements with equal names use integer to identify which element should be used :return obj: value """ with open(yaml_file, 'r') as f_old: yaml_dict = yaml.load(f_old) for i, k in enumerate(element): try: yaml_dict = yaml_dict[k] except IndexError: raise IndexError("Element {0} not found in the file {1}" .format(element[: i + 1], f_old)) except KeyError: raise KeyError("Element {0} not found in the file {1}" .format(element[: i + 1], f_old)) return yaml_dict def change_remote_yaml(self, path_to_file, element, value): """Changes values in the yaml file stored There is no need to copy file manually :param path_to_file: absolute path to the file :param element: list with path to the element be changed :param value: new value for element :return: Nothing """ old_file = '/tmp/temp_file_{0}.old.yaml'.format(str(os.getpid())) new_file = '/tmp/temp_file_{0}.new.yaml'.format(str(os.getpid())) self.ssh_manager.download_from_remote( ip=self.admin_ip, destination=path_to_file, target=old_file ) self.put_value_to_local_yaml(old_file, new_file, element, value) self.ssh_manager.upload_to_remote( ip=self.admin_ip, source=new_file, target=path_to_file ) os.remove(old_file) os.remove(new_file) def get_value_from_remote_yaml(self, path_to_file, element): """Get a value from the yaml file stored on the master node :param str path_to_file: absolute path to the file :param list element: list with path to the element :return obj: value """ host_tmp_file = '/tmp/temp_file_{0}.yaml'.format(str(os.getpid())) self.ssh_manager.download_from_remote( ip=self.admin_ip, destination=path_to_file, target=host_tmp_file ) value = self.get_value_from_local_yaml(host_tmp_file, element) os.remove(host_tmp_file) return value def put_value_to_remote_yaml(self, path_to_file, element, value): """Put a value to the yaml file stored on the master node :param str path_to_file: absolute path to the file :param list element: list with path to the element be changed :param value: new value for element :return: None """ host_tmp_file = '/tmp/temp_file_{0}.yaml'.format(str(os.getpid())) self.ssh_manager.download_from_remote( ip=self.admin_ip, destination=path_to_file, target=host_tmp_file ) self.put_value_to_local_yaml(host_tmp_file, host_tmp_file, element, value) self.ssh_manager.upload_to_remote( ip=self.admin_ip, source=host_tmp_file, target=path_to_file ) os.remove(host_tmp_file)
class BaseActions(object): """BaseActions.""" # TODO documentation def __init__(self): self.ssh_manager = SSHManager() self.admin_ip = self.ssh_manager.admin_ip self.container = None def __repr__(self): klass, obj_id = type(self), hex(id(self)) container = getattr(self, 'container', None) return "[{klass}({obj_id}), container:{container}]".format( klass=klass, obj_id=obj_id, container=container) def execute_in_container(self, command, container=None, exit_code=None, stdin=None): if not container: container = self.container cmd = 'dockerctl shell {0} {1}'.format(container, command) if stdin is not None: cmd = 'echo "{0}" | {1}'.format(stdin, cmd) result = self.ssh_manager.execute( ip=self.admin_ip, cmd=cmd ) if exit_code is not None: assert_equal(exit_code, result['exit_code'], ('Command {cmd} returned exit code "{e}", but ' 'expected "{c}". Output: {out}; {err} ').format( cmd=cmd, e=result['exit_code'], c=exit_code, out=result['stdout'], err=result['stderr'] )) return ''.join(result['stdout']).strip() def copy_between_node_and_container(self, copy_from, copy_to): """ Copy files from/to container. :param copy_from: path to copy file from :param copy_to: path to copy file to For ex.: - to copy from container to master node use: copy_from = container:path_from copy_to = path_to - to copy from master node to container use: copy_from = path_from copy_to = container:path_to :return: Standard output from console """ cmd = 'dockerctl copy {0} {1}'.format(copy_from, copy_to) result = self.ssh_manager.execute( ip=self.admin_ip, cmd=cmd ) assert_equal(0, result['exit_code'], ('Command copy returned exit code "{e}", but ' 'expected "0". Output: {out}; {err} ').format( cmd=cmd, e=result['exit_code'], out=result['stdout'], err=result['stderr'])) return ''.join(result['stdout']).strip() @property def is_container_ready(self): result = self.ssh_manager.execute( ip=self.admin_ip, cmd="timeout 5 dockerctl check {0}".format(self.container) ) return result['exit_code'] == 0 def wait_for_ready_container(self, timeout=300): wait(lambda: self.is_container_ready, timeout=timeout) def put_value_to_local_yaml(self, old_file, new_file, element, value): """Changes content in old_file at element is given to the new value and creates new file with changed content :param old_file: a path to the file content from to be changed :param new_file: a path to the new file to ve created with new content :param element: tuple with path to element to be changed for example: ['root_elem', 'first_elem', 'target_elem'] if there are a few elements with equal names use integer to identify which element should be used :return: nothing """ with open(old_file, 'r') as f_old: yaml_dict = yaml.load(f_old) origin_yaml = yaml_dict for k in element[:-1]: yaml_dict = yaml_dict[k] yaml_dict[element[-1]] = value with open(new_file, 'w') as f_new: yaml.dump(origin_yaml, f_new, default_flow_style=False, default_style='"') def get_value_from_local_yaml(self, yaml_file, element): """Get a value of the element from the local yaml file :param str yaml_file: a path to the yaml file :param list element: list with path to element to be read for example: ['root_elem', 'first_elem', 'target_elem'] if there are a few elements with equal names use integer to identify which element should be used :return obj: value """ with open(yaml_file, 'r') as f_old: yaml_dict = yaml.load(f_old) for i, k in enumerate(element): try: yaml_dict = yaml_dict[k] except IndexError: raise IndexError("Element {0} not found in the file {1}" .format(element[: i + 1], f_old)) except KeyError: raise KeyError("Element {0} not found in the file {1}" .format(element[: i + 1], f_old)) return yaml_dict def change_yaml_file_in_container( self, path_to_file, element, value, container=None): """Changes values in the yaml file stored at container There is no need to copy file manually :param path_to_file: absolutely path to the file :param element: list with path to the element be changed :param value: new value for element :param container: Container with file. By default it is nailgun :return: Nothing """ if not container: container = self.container old_file = '/tmp/temp_file_{0}.old.yaml'.format(str(os.getpid())) new_file = '/tmp/temp_file_{0}.new.yaml'.format(str(os.getpid())) self.copy_between_node_and_container( '{0}:{1}'.format(container, path_to_file), old_file) self.ssh_manager.download_from_remote( ip=self.admin_ip, destination=old_file, target=old_file ) self.put_value_to_local_yaml(old_file, new_file, element, value) self.ssh_manager.upload_to_remote( ip=self.admin_ip, source=new_file, target=new_file ) self.copy_between_node_and_container( new_file, '{0}:{1}'.format(container, path_to_file)) os.remove(old_file) os.remove(new_file) def get_value_from_yaml(self, path_to_file, element): """Get a value from the yaml file stored in container or on master node if self.container is None :param str path_to_file: absolutely path to the file :param list element: list with path to the element be changed :return obj: value """ if self.container: admin_tmp_file = '/tmp/temp_file_{0}.yaml'.format(str(os.getpid())) self.copy_between_node_and_container( '{0}:{1}'.format(self.container, path_to_file), admin_tmp_file) else: admin_tmp_file = path_to_file host_tmp_file = '/tmp/temp_file_{0}.yaml'.format(str(os.getpid())) self.ssh_manager.download_from_remote( ip=self.admin_ip, destination=admin_tmp_file, target=host_tmp_file ) value = self.get_value_from_local_yaml(host_tmp_file, element) os.remove(host_tmp_file) return value def put_value_to_yaml(self, path_to_file, element, value): """Put a value to the yaml file stored in container or on master node if self.container is None :param str path_to_file: absolutely path to the file :param list element: list with path to the element be changed :param value: new value for element :return: None """ if self.container: admin_tmp_file = '/tmp/temp_file_{0}.yaml'.format(str(os.getpid())) self.copy_between_node_and_container( '{0}:{1}'.format(self.container, path_to_file), admin_tmp_file) else: admin_tmp_file = path_to_file host_tmp_file = '/tmp/temp_file_{0}.yaml'.format(str(os.getpid())) self.ssh_manager.download_from_remote( ip=self.admin_ip, destination=admin_tmp_file, target=host_tmp_file ) self.put_value_to_local_yaml(host_tmp_file, host_tmp_file, element, value) self.ssh_manager.upload_to_remote( ip=self.admin_ip, source=host_tmp_file, target=admin_tmp_file ) if self.container: self.copy_between_node_and_container( admin_tmp_file, '{0}:{1}'.format(self.container, path_to_file)) os.remove(host_tmp_file)
class CustomRepo(object): """CustomRepo.""" # TODO documentation def __init__(self): self.ssh_manager = SSHManager() self.ip = self.ssh_manager.admin_ip self.path_scripts = ('{0}/fuelweb_test/helpers/' .format(os.environ.get("WORKSPACE", "./"))) self.remote_path_scripts = '/tmp/' self.ubuntu_script = 'regenerate_ubuntu_repo' self.centos_script = 'regenerate_centos_repo' self.local_mirror_ubuntu = settings.LOCAL_MIRROR_UBUNTU self.local_mirror_centos = settings.LOCAL_MIRROR_CENTOS self.ubuntu_release = settings.UBUNTU_RELEASE self.centos_supported_archs = ['noarch', 'x86_64'] self.pkgs_list = [] self.custom_pkgs_mirror_path = '' if settings.OPENSTACK_RELEASE_UBUNTU in settings.OPENSTACK_RELEASE: # Trying to determine the root of Ubuntu repository pkgs_path = settings.CUSTOM_PKGS_MIRROR.split('/dists/') if len(pkgs_path) == 2: self.custom_pkgs_mirror = pkgs_path[0] self.custom_pkgs_mirror_path = '/dists/{}'.format(pkgs_path[1]) else: self.custom_pkgs_mirror = settings.CUSTOM_PKGS_MIRROR else: self.custom_pkgs_mirror = settings.CUSTOM_PKGS_MIRROR def prepare_repository(self): """Prepare admin node to packages testing Scenario: 1. Temporary set nameserver to local router on admin node 2. Install tools to manage rpm/deb repository 3. Retrieve list of packages from custom repository 4. Download packages to local rpm/deb repository 5. Update .yaml file with new packages version 6. Re-generate repo using shell scripts on admin node """ # Check necessary settings and revert a snapshot if not self.custom_pkgs_mirror: return logger.info("Custom mirror with new packages: {0}" .format(settings.CUSTOM_PKGS_MIRROR)) if settings.OPENSTACK_RELEASE_UBUNTU in settings.OPENSTACK_RELEASE: # Ubuntu master_tools = ['dpkg', 'dpkg-devel', 'dpkg-dev'] self.install_tools(master_tools) self.get_pkgs_list_ubuntu() pkgs_local_path = ('{0}/pool/' .format(self.local_mirror_ubuntu)) self.download_pkgs(pkgs_local_path) self.regenerate_repo(self.ubuntu_script, self.local_mirror_ubuntu) else: # CentOS master_tools = ['createrepo'] self.install_tools(master_tools) self.get_pkgs_list_centos() pkgs_local_path = '{0}/Packages/'.format(self.local_mirror_centos) self.download_pkgs(pkgs_local_path) self.regenerate_repo(self.centos_script, self.local_mirror_centos) # Install tools to masternode def install_tools(self, master_tools=None): if master_tools is None: master_tools = [] logger.info("Installing necessary tools for {0}" .format(settings.OPENSTACK_RELEASE)) for master_tool in master_tools: exit_code = install_pkg_2( ip=self.ip, pkg_name=master_tool ) assert_equal(0, exit_code, 'Cannot install package {0} ' 'on admin node.'.format(master_tool)) # Ubuntu: Creating list of packages from the additional mirror def get_pkgs_list_ubuntu(self): url = "{0}/{1}/Packages".format(self.custom_pkgs_mirror, self.custom_pkgs_mirror_path) logger.info("Retrieving additional packages from the custom mirror:" " {0}".format(url)) try: pkgs_release = urlopen(url).read() except (HTTPError, URLError): logger.error(traceback.format_exc()) url_gz = '{0}.gz'.format(url) logger.info( "Retrieving additional packages from the custom mirror:" " {0}".format(url_gz)) try: pkgs_release_gz = urlopen(url_gz).read() except (HTTPError, URLError): logger.error(traceback.format_exc()) raise try: d = zlib.decompressobj(zlib.MAX_WBITS | 32) pkgs_release = d.decompress(pkgs_release_gz) except Exception: logger.error('Ubuntu mirror error: Could not decompress {0}\n' '{1}'.format(url_gz, traceback.format_exc())) raise packages = (pkg for pkg in pkgs_release.split("\n\n") if pkg) for package in packages: upkg = {pstr.split()[0].lower(): ''.join(pstr.split()[1:]) for pstr in package.split("\n") if pstr[0].strip()} upkg_keys = ["package:", "version:", "filename:"] assert_equal(True, all(x in upkg for x in upkg_keys), 'Missing one of the statements ["Package:", ' '"Version:", "Filename:"] in {0}'.format(url)) # TODO: add dependencies list to upkg self.pkgs_list.append(upkg) # Centos: Creating list of packages from the additional mirror def get_pkgs_list_centos(self): logger.info("Retrieving additional packages from the custom mirror:" " {0}".format(self.custom_pkgs_mirror)) url = "{0}/repodata/repomd.xml".format(self.custom_pkgs_mirror) try: repomd_data = urlopen(url).read() except (HTTPError, URLError): logger.error(traceback.format_exc()) raise # Remove namespace attribute before parsing XML repomd_data = re.sub(' xmlns="[^"]+"', '', repomd_data, count=1) tree_repomd_data = ElementTree.fromstring(repomd_data) lists_location = '' for repomd in tree_repomd_data.findall('data'): if repomd.get('type') == 'primary': repomd_location = repomd.find('location') lists_location = repomd_location.get('href') assert_equal(True, lists_location is not '', 'CentOS mirror error:' ' Could not parse {0}\nlists_location = "{1}"\n{2}' .format(url, lists_location, traceback.format_exc())) url = "{0}/{1}".format(self.custom_pkgs_mirror, lists_location) try: lists_data = urlopen(url).read() except (HTTPError, URLError): logger.error(traceback.format_exc()) raise if '.xml.gz' in lists_location: try: d = zlib.decompressobj(zlib.MAX_WBITS | 32) lists_data = d.decompress(lists_data) except Exception: logger.error('CentOS mirror error: Could not decompress {0}\n' '{1}'.format(url, traceback.format_exc())) raise # Remove namespace attribute before parsing XML lists_data = re.sub(' xmlns="[^"]+"', '', lists_data, count=1) tree_lists_data = ElementTree.fromstring(lists_data) for flist in tree_lists_data.findall('package'): if flist.get('type') == 'rpm': flist_arch = flist.find('arch').text if flist_arch in self.centos_supported_archs: flist_name = flist.find('name').text flist_location = flist.find('location') flist_file = flist_location.get('href') flist_version = flist.find('version') flist_ver = '{0}-{1}'.format(flist_version.get('ver'), flist_version.get('rel')) cpkg = {'package:': flist_name, 'version:': flist_ver, 'filename:': flist_file} # TODO: add dependencies list to cpkg self.pkgs_list.append(cpkg) # Download packages (local_folder) def download_pkgs(self, pkgs_local_path): # Process the packages list: total_pkgs = len(self.pkgs_list) logger.info('Found {0} custom package(s)'.format(total_pkgs)) for npkg, pkg in enumerate(self.pkgs_list): # TODO: Previous versions of the updating packages must be removed # to avoid unwanted packet manager dependencies resolution # (when some package still depends on other package which # is not going to be installed) logger.info('({0}/{1}) Downloading package: {2}/{3}' .format(npkg + 1, total_pkgs, self.custom_pkgs_mirror, pkg["filename:"])) pkg_ext = pkg["filename:"].split('.')[-1] if pkg_ext == 'deb': path_suff = 'main/' elif pkg_ext == 'udeb': path_suff = 'debian-installer/' else: path_suff = '' wget_cmd = "wget --no-verbose --directory-prefix {0} {1}/{2}"\ .format(pkgs_local_path + path_suff, self.custom_pkgs_mirror, pkg["filename:"]) wget_result = self.ssh_manager.execute( ip=self.ip, cmd=wget_cmd ) assert_equal(0, wget_result['exit_code'], self.assert_msg(wget_cmd, wget_result['stderr'])) # Upload regenerate* script to masternode (script name) def regenerate_repo(self, regenerate_script, local_mirror_path): # Uploading scripts that prepare local repositories: # 'regenerate_centos_repo' and 'regenerate_ubuntu_repo' try: self.ssh_manager.upload_to_remote( ip=self.ip, source='{0}/{1}'.format(self.path_scripts, regenerate_script), target=self.remote_path_scripts ) self.ssh_manager.execute_on_remote( ip=self.ip, cmd='chmod 755 {0}/{1}'.format(self.remote_path_scripts, regenerate_script) ) except Exception: logger.error('Could not upload scripts for updating repositories.' '\n{0}'.format(traceback.format_exc())) raise # Update the local repository using previously uploaded script. script_cmd = '{0}/{1} {2} {3}'.format(self.remote_path_scripts, regenerate_script, local_mirror_path, self.ubuntu_release) script_result = self.ssh_manager.execute( ip=self.ip, cmd=script_cmd ) assert_equal(0, script_result['exit_code'], self.assert_msg(script_cmd, script_result['stderr'])) logger.info('Local repository {0} has been updated successfully.' .format(local_mirror_path)) @staticmethod def assert_msg(cmd, err): return 'Executing \'{0}\' on the admin node has failed with: {1}'\ .format(cmd, err) def check_puppet_logs(self): logger.info("Check puppet logs for packages with unmet dependencies.") if settings.OPENSTACK_RELEASE_UBUNTU in settings.OPENSTACK_RELEASE: err_deps = self.check_puppet_logs_ubuntu() else: err_deps = self.check_puppet_logs_centos() for err_deps_key in err_deps.keys(): logger.info('Error: Package: {0} has unmet dependencies:' .format(err_deps_key)) for dep in err_deps[err_deps_key]: logger.info(' {0}'.format(dep.strip())) logger.info("Check puppet logs completed.") def check_puppet_logs_ubuntu(self): """ Check puppet-agent.log files on all nodes for package dependency errors during a cluster deployment (ubuntu)""" err_start = 'The following packages have unmet dependencies:' err_end = ('Unable to correct problems,' ' you have held broken packages.') cmd = ('fgrep -h -e " Depends: " -e "{0}" -e "{1}" ' '/var/log/remote/node-*/' 'puppet*.log'.format(err_start, err_end)) result = self.ssh_manager.execute( ip=self.ip, cmd=cmd )['stdout'] err_deps = {} err_deps_key = '' err_deps_flag = False # Forming a dictionary of package names # with sets of required packages. for res_str in result: if err_deps_flag: if err_end in res_str: err_deps_flag = False elif ": Depends:" in res_str: str0, str1, str2 = res_str.partition(': Depends:') err_deps_key = ''.join(str0.split()[-1:]) if err_deps_key not in err_deps: err_deps[err_deps_key] = set() if 'but it is not' in str2 or 'is to be installed' in str2: err_deps[err_deps_key].add('Depends:{0}' .format(str2)) elif 'Depends:' in res_str and err_deps_key: str0, str1, str2 = res_str.partition('Depends:') if 'but it is not' in str2 or 'is to be installed' in str2: err_deps[err_deps_key].add(str1 + str2) else: err_deps_key = '' elif err_start in res_str: err_deps_flag = True return err_deps def check_puppet_logs_centos(self): """ Check puppet-agent.log files on all nodes for package dependency errors during a cluster deployment (centos)""" cmd = ('fgrep -h -e "Error: Package: " -e " Requires: " /var/log/' 'remote/node-*/puppet*.log') result = self.ssh_manager.execute( ip=self.ip, cmd=cmd )['stdout'] err_deps = {} err_deps_key = '' # Forming a dictionary of package names # with sets of required packages. for res_str in result: if 'Error: Package:' in res_str: err_deps_key = res_str.partition('Error: Package: ')[2] if err_deps_key not in err_deps: err_deps[err_deps_key] = set() elif ' Requires: ' in res_str and err_deps_key: _, str1, str2 = res_str.partition(' Requires: ') err_deps[err_deps_key].add(str1 + str2) else: err_deps_key = '' return err_deps
def replace_fuel_nailgun_rpm(): """ Replace fuel_nailgun*.rpm from review """ logger.info("Patching fuel-nailgun") ssh = SSHManager() if not settings.UPDATE_FUEL: raise exceptions.FuelQAVariableNotSet('UPDATE_FUEL', 'True') pack_path = '/var/www/nailgun/fuel-nailgun/' full_pack_path = os.path.join(pack_path, 'fuel-nailgun*.noarch.rpm') logger.info('Package path {0}'.format(full_pack_path)) ssh.upload_to_remote( ip=ssh.admin_ip, source=settings.UPDATE_FUEL_PATH.rstrip('/'), target=pack_path) # Check old fuel-nailgun package cmd = "rpm -q fuel-nailgun" old_package = ssh.execute_on_remote( ip=ssh.admin_ip, cmd=cmd)['stdout_str'] logger.info( 'Current package version of ' 'fuel-nailgun: {0}'.format(old_package)) cmd = "rpm -qp {0}".format(full_pack_path) new_package = ssh.execute_on_remote( ip=ssh.admin_ip, cmd=cmd)['stdout_str'] logger.info("Updating package {0} with {1}".format( old_package, new_package)) if old_package == new_package: logger.debug('Looks like package from review ' 'was installed during setups of master node') return # stop services service_list = ['assassind', 'receiverd', 'nailgun', 'statsenderd'] for service in service_list: ssh.execute_on_remote( ip=ssh.admin_ip, cmd='systemctl stop {0}'.format(service)) logger.info('statistic services {0}'.format(get_oswl_services_names())) # stop statistic services for service in get_oswl_services_names(): ssh.execute_on_remote( ip=ssh.admin_ip, cmd='systemctl stop {0}'.format(service)) # Drop nailgun db manage.py dropdb cmd = 'manage.py dropdb' ssh.execute_on_remote(ssh.admin_ip, cmd) # Delete package logger.info("Delete package {0}".format(old_package)) cmd = "rpm -e fuel-nailgun" ssh.execute_on_remote(ssh.admin_ip, cmd) logger.info("Install package {0}".format(new_package)) cmd = "rpm -Uvh --oldpackage {0}".format(full_pack_path) ssh.execute_on_remote(ssh.admin_ip, cmd) cmd = "rpm -q fuel-nailgun" installed_package = ssh.execute_on_remote(ssh.admin_ip, cmd)['stdout_str'] assert_equal(installed_package, new_package, "The new package {0} was not installed".format(new_package)) cmd = ('puppet apply --debug ' '/etc/puppet/modules/fuel/examples/nailgun.pp') ssh.execute_on_remote(ssh.admin_ip, cmd) cmd_sync = 'fuel release --sync-deployment-tasks --dir /etc/puppet/' ssh.execute_on_remote(ssh.admin_ip, cmd=cmd_sync)
class BaseActions(object): """BaseActions.""" # TODO documentation def __init__(self): self.ssh_manager = SSHManager() self.admin_ip = self.ssh_manager.admin_ip def __repr__(self): klass, obj_id = type(self), hex(id(self)) return "[{klass}({obj_id})]".format( klass=klass, obj_id=obj_id) # TODO(kozhukalov): This method seems not needed and # can easily be replaced by using execute_on_remote # available in SSHManager (up to the type of return value) def execute(self, cmd, exit_code=None, stdin=None): if stdin is not None: cmd = 'echo "{0}" | {1}'.format(stdin, cmd) result = self.ssh_manager.execute( ip=self.admin_ip, cmd=cmd ) if exit_code is not None: assert_equal(exit_code, result['exit_code'], ('Command {cmd} returned exit code "{e}", but ' 'expected "{c}". Output: {out}; {err} ').format( cmd=cmd, e=result['exit_code'], c=exit_code, out=result['stdout'], err=result['stderr'] )) return ''.join(result['stdout']).strip() def restart_service(self, service): result = self.ssh_manager( ip=self.admin_ip, cmd="systemctl restart {0}".format(service)) return result['exit_code'] == 0 def put_value_to_local_yaml(self, old_file, new_file, element, value): """Changes content in old_file at element is given to the new value and creates new file with changed content :param old_file: a path to the file content from to be changed :param new_file: a path to the new file to ve created with new content :param element: tuple with path to element to be changed for example: ['root_elem', 'first_elem', 'target_elem'] if there are a few elements with equal names use integer to identify which element should be used :return: nothing """ with open(old_file, 'r') as f_old: yaml_dict = yaml.load(f_old) origin_yaml = yaml_dict for k in element[:-1]: yaml_dict = yaml_dict[k] yaml_dict[element[-1]] = value with open(new_file, 'w') as f_new: yaml.dump(origin_yaml, f_new, default_flow_style=False, default_style='"') def get_value_from_local_yaml(self, yaml_file, element): """Get a value of the element from the local yaml file :param str yaml_file: a path to the yaml file :param list element: list with path to element to be read for example: ['root_elem', 'first_elem', 'target_elem'] if there are a few elements with equal names use integer to identify which element should be used :return obj: value """ with open(yaml_file, 'r') as f_old: yaml_dict = yaml.load(f_old) for i, k in enumerate(element): try: yaml_dict = yaml_dict[k] except IndexError: raise IndexError("Element {0} not found in the file {1}" .format(element[: i + 1], f_old)) except KeyError: raise KeyError("Element {0} not found in the file {1}" .format(element[: i + 1], f_old)) return yaml_dict def change_remote_yaml(self, path_to_file, element, value): """Changes values in the yaml file stored There is no need to copy file manually :param path_to_file: absolute path to the file :param element: list with path to the element be changed :param value: new value for element :return: Nothing """ old_file = '/tmp/temp_file_{0}.old.yaml'.format(str(os.getpid())) new_file = '/tmp/temp_file_{0}.new.yaml'.format(str(os.getpid())) self.ssh_manager.download_from_remote( ip=self.admin_ip, destination=path_to_file, target=old_file ) self.put_value_to_local_yaml(old_file, new_file, element, value) self.ssh_manager.upload_to_remote( ip=self.admin_ip, source=new_file, target=path_to_file ) os.remove(old_file) os.remove(new_file) def get_value_from_remote_yaml(self, path_to_file, element): """Get a value from the yaml file stored on the master node :param str path_to_file: absolute path to the file :param list element: list with path to the element :return obj: value """ host_tmp_file = '/tmp/temp_file_{0}.yaml'.format(str(os.getpid())) self.ssh_manager.download_from_remote( ip=self.admin_ip, destination=path_to_file, target=host_tmp_file ) value = self.get_value_from_local_yaml(host_tmp_file, element) os.remove(host_tmp_file) return value def put_value_to_remote_yaml(self, path_to_file, element, value): """Put a value to the yaml file stored on the master node :param str path_to_file: absolute path to the file :param list element: list with path to the element be changed :param value: new value for element :return: None """ host_tmp_file = '/tmp/temp_file_{0}.yaml'.format(str(os.getpid())) self.ssh_manager.download_from_remote( ip=self.admin_ip, destination=path_to_file, target=host_tmp_file ) self.put_value_to_local_yaml(host_tmp_file, host_tmp_file, element, value) self.ssh_manager.upload_to_remote( ip=self.admin_ip, source=host_tmp_file, target=path_to_file ) os.remove(host_tmp_file)
def check_package_version_injected_in_bootstraps( package, cluster_id=None, ironic=None): ssh = SSHManager() try: pack_path = '/var/www/nailgun/{}/'.format(package) ssh.upload_to_remote( ip=ssh.admin_ip, source=settings.UPDATE_FUEL_PATH.rstrip('/'), target=pack_path) except Exception: logger.exception("Could not upload package") raise # Step 1 - unpack active bootstrap logger.info("unpack active bootstrap") if ironic: bootstrap = "/var/www/nailgun/bootstrap/ironic/{}".format(cluster_id) else: bootstrap = "/var/www/nailgun/bootstraps/active_bootstrap" bootstrap_var = "/var/root.squashfs" cmd = "unsquashfs -d {} {}/root.squashfs".format( bootstrap_var, bootstrap) ssh.execute_on_remote( ip=ssh.admin_ip, cmd=cmd) # Step 2 - check package version logger.info( "check package {} version injected in ubuntu bootstrap".format( package)) cmd = "ls {}|grep {} |grep deb |cut -f 2 -d '_'".format( pack_path, package) package_from_review = ssh.execute_on_remote( ip=ssh.admin_ip, cmd=cmd)['stdout_str'] logger.info("package from review is {}".format(package_from_review)) awk_pattern = "awk '{print $2}'" cmd = "chroot {}/ /bin/bash -c \"dpkg -s {}\"|grep Version|{}".format( bootstrap_var, package, awk_pattern) installed_package = ssh.execute_on_remote( ip=ssh.admin_ip, cmd=cmd)['stdout_str'] logger.info("injected package is {}".format(installed_package)) assert_equal(installed_package, package_from_review, "The new package {0} wasn't injected in bootstrap".format( package_from_review)) # Step 3 - remove unpacked bootstrap cmd = "rm -rf {}".format(bootstrap_var) ssh.execute_on_remote( ip=ssh.admin_ip, cmd=cmd)
class BaseActions(object): """BaseActions.""" # TODO documentation def __init__(self): self.ssh_manager = SSHManager() self.admin_ip = self.ssh_manager.admin_ip self.container = None def __repr__(self): klass, obj_id = type(self), hex(id(self)) container = getattr(self, 'container', None) return "[{klass}({obj_id}), container:{container}]".format( klass=klass, obj_id=obj_id, container=container) def execute_in_container(self, command, container=None, exit_code=None, stdin=None): if not container: container = self.container cmd = 'dockerctl shell {0} {1}'.format(container, command) if stdin is not None: cmd = 'echo "{0}" | {1}'.format(stdin, cmd) result = self.ssh_manager.execute(ip=self.admin_ip, cmd=cmd) if exit_code is not None: assert_equal(exit_code, result['exit_code'], ('Command {cmd} returned exit code "{e}", but ' 'expected "{c}". Output: {out}; {err} ').format( cmd=cmd, e=result['exit_code'], c=exit_code, out=result['stdout'], err=result['stderr'])) return ''.join(result['stdout']).strip() def copy_between_node_and_container(self, copy_from, copy_to): """ Copy files from/to container. :param copy_from: path to copy file from :param copy_to: path to copy file to For ex.: - to copy from container to master node use: copy_from = container:path_from copy_to = path_to - to copy from master node to container use: copy_from = path_from copy_to = container:path_to :return: Standard output from console """ cmd = 'dockerctl copy {0} {1}'.format(copy_from, copy_to) result = self.ssh_manager.execute(ip=self.admin_ip, cmd=cmd) assert_equal(0, result['exit_code'], ('Command copy returned exit code "{e}", but ' 'expected "0". Output: {out}; {err} ').format( cmd=cmd, e=result['exit_code'], out=result['stdout'], err=result['stderr'])) return ''.join(result['stdout']).strip() @property def is_container_ready(self): result = self.ssh_manager.execute( ip=self.admin_ip, cmd="timeout 5 dockerctl check {0}".format(self.container)) return result['exit_code'] == 0 def wait_for_ready_container(self, timeout=300): wait(lambda: self.is_container_ready, timeout=timeout) def put_value_to_local_yaml(self, old_file, new_file, element, value): """Changes content in old_file at element is given to the new value and creates new file with changed content :param old_file: a path to the file content from to be changed :param new_file: a path to the new file to ve created with new content :param element: tuple with path to element to be changed for example: ['root_elem', 'first_elem', 'target_elem'] if there are a few elements with equal names use integer to identify which element should be used :return: nothing """ with open(old_file, 'r') as f_old: yaml_dict = yaml.load(f_old) origin_yaml = yaml_dict for k in element[:-1]: yaml_dict = yaml_dict[k] yaml_dict[element[-1]] = value with open(new_file, 'w') as f_new: yaml.dump(origin_yaml, f_new, default_flow_style=False, default_style='"') def get_value_from_local_yaml(self, yaml_file, element): """Get a value of the element from the local yaml file :param str yaml_file: a path to the yaml file :param list element: list with path to element to be read for example: ['root_elem', 'first_elem', 'target_elem'] if there are a few elements with equal names use integer to identify which element should be used :return obj: value """ with open(yaml_file, 'r') as f_old: yaml_dict = yaml.load(f_old) for i, k in enumerate(element): try: yaml_dict = yaml_dict[k] except IndexError: raise IndexError( "Element {0} not found in the file {1}".format( element[:i + 1], f_old)) except KeyError: raise KeyError("Element {0} not found in the file {1}".format( element[:i + 1], f_old)) return yaml_dict def change_yaml_file_in_container(self, path_to_file, element, value, container=None): """Changes values in the yaml file stored at container There is no need to copy file manually :param path_to_file: absolutely path to the file :param element: list with path to the element be changed :param value: new value for element :param container: Container with file. By default it is nailgun :return: Nothing """ if not container: container = self.container old_file = '/tmp/temp_file_{0}.old.yaml'.format(str(os.getpid())) new_file = '/tmp/temp_file_{0}.new.yaml'.format(str(os.getpid())) self.copy_between_node_and_container( '{0}:{1}'.format(container, path_to_file), old_file) self.ssh_manager.download_from_remote(ip=self.admin_ip, destination=old_file, target=old_file) self.put_value_to_local_yaml(old_file, new_file, element, value) self.ssh_manager.upload_to_remote(ip=self.admin_ip, source=new_file, target=new_file) self.copy_between_node_and_container( new_file, '{0}:{1}'.format(container, path_to_file)) os.remove(old_file) os.remove(new_file) def get_value_from_yaml(self, path_to_file, element): """Get a value from the yaml file stored in container or on master node if self.container is None :param str path_to_file: absolutely path to the file :param list element: list with path to the element be changed :return obj: value """ if self.container: admin_tmp_file = '/tmp/temp_file_{0}.yaml'.format(str(os.getpid())) self.copy_between_node_and_container( '{0}:{1}'.format(self.container, path_to_file), admin_tmp_file) else: admin_tmp_file = path_to_file host_tmp_file = '/tmp/temp_file_{0}.yaml'.format(str(os.getpid())) self.ssh_manager.download_from_remote(ip=self.admin_ip, destination=admin_tmp_file, target=host_tmp_file) value = self.get_value_from_local_yaml(host_tmp_file, element) os.remove(host_tmp_file) return value def put_value_to_yaml(self, path_to_file, element, value): """Put a value to the yaml file stored in container or on master node if self.container is None :param str path_to_file: absolutely path to the file :param list element: list with path to the element be changed :param value: new value for element :return: None """ if self.container: admin_tmp_file = '/tmp/temp_file_{0}.yaml'.format(str(os.getpid())) self.copy_between_node_and_container( '{0}:{1}'.format(self.container, path_to_file), admin_tmp_file) else: admin_tmp_file = path_to_file host_tmp_file = '/tmp/temp_file_{0}.yaml'.format(str(os.getpid())) self.ssh_manager.download_from_remote(ip=self.admin_ip, destination=admin_tmp_file, target=host_tmp_file) self.put_value_to_local_yaml(host_tmp_file, host_tmp_file, element, value) self.ssh_manager.upload_to_remote(ip=self.admin_ip, source=host_tmp_file, target=admin_tmp_file) if self.container: self.copy_between_node_and_container( admin_tmp_file, '{0}:{1}'.format(self.container, path_to_file)) os.remove(host_tmp_file)
def replace_fuel_nailgun_rpm(): """ Replace fuel_nailgun*.rpm from review """ logger.info("Patching fuel-nailgun") ssh = SSHManager() if not settings.UPDATE_FUEL: raise exceptions.FuelQAVariableNotSet('UPDATE_FUEL', 'True') pack_path = '/var/www/nailgun/fuel-nailgun/' full_pack_path = os.path.join(pack_path, 'fuel-nailgun*.noarch.rpm') logger.info('Package path {0}'.format(full_pack_path)) ssh.upload_to_remote(ip=ssh.admin_ip, source=settings.UPDATE_FUEL_PATH.rstrip('/'), target=pack_path) # Check old fuel-nailgun package cmd = "rpm -q fuel-nailgun" old_package = ssh.execute_on_remote(ip=ssh.admin_ip, cmd=cmd)['stdout_str'] logger.info('Current package version of ' 'fuel-nailgun: {0}'.format(old_package)) cmd = "rpm -qp {0}".format(full_pack_path) new_package = ssh.execute_on_remote(ip=ssh.admin_ip, cmd=cmd)['stdout_str'] logger.info("Updating package {0} with {1}".format(old_package, new_package)) if old_package == new_package: logger.debug('Looks like package from review ' 'was installed during setups of master node') return # stop services service_list = ['assassind', 'receiverd', 'nailgun', 'statsenderd'] for service in service_list: ssh.execute_on_remote(ip=ssh.admin_ip, cmd='systemctl stop {0}'.format(service)) logger.info('statistic services {0}'.format(get_oswl_services_names())) # stop statistic services for service in get_oswl_services_names(): ssh.execute_on_remote(ip=ssh.admin_ip, cmd='systemctl stop {0}'.format(service)) # Drop nailgun db manage.py dropdb cmd = 'manage.py dropdb' ssh.execute_on_remote(ssh.admin_ip, cmd) # Delete package logger.info("Delete package {0}".format(old_package)) cmd = "rpm -e fuel-nailgun" ssh.execute_on_remote(ssh.admin_ip, cmd) logger.info("Install package {0}".format(new_package)) cmd = "rpm -Uvh --oldpackage {0}".format(full_pack_path) ssh.execute_on_remote(ssh.admin_ip, cmd) cmd = "rpm -q fuel-nailgun" installed_package = ssh.execute_on_remote(ssh.admin_ip, cmd)['stdout_str'] assert_equal(installed_package, new_package, "The new package {0} was not installed".format(new_package)) cmd = ('puppet apply --debug ' '/etc/puppet/modules/fuel/examples/nailgun.pp') ssh.execute_on_remote(ssh.admin_ip, cmd) cmd_sync = 'fuel release --sync-deployment-tasks --dir /etc/puppet/' ssh.execute_on_remote(ssh.admin_ip, cmd=cmd_sync)