diff --git a/sw-patch/bin/setup_patch_repo b/sw-patch/bin/setup_patch_repo index a9eb1c521..aecd9e79e 100755 --- a/sw-patch/bin/setup_patch_repo +++ b/sw-patch/bin/setup_patch_repo @@ -135,45 +135,6 @@ def main(): # Purge unneeded RPMs keep = {} - for patch_id in allpatches.metadata.keys(): - for rpmname in allpatches.contents[patch_id]: - try: - pkgname, arch, pkgver = pf.parse_rpm_filename(rpmname) - except ValueError as e: - raise e - - if pkgname not in keep: - keep[pkgname] = { arch: pkgver } - continue - elif arch not in keep[pkgname]: - keep[pkgname][arch] = pkgver - continue - - # Compare versions - keep_pkgver = keep[pkgname][arch] - if pkgver > keep_pkgver: - # Find the rpmname - keep_rpmname = keep_pkgver.generate_rpm_filename(pkgname, arch) - - filename = os.path.join(pkgdir, keep_rpmname) - if os.path.exists(filename): - os.remove(filename) - - # Keep the new pkgver - keep[pkgname][arch] = pkgver - else: - filename = os.path.join(pkgdir, rpmname) - if os.path.exists(filename): - os.remove(filename) - - # Create the repo metadata - if os.path.exists('/usr/bin/createrepo_c'): - createrepo = '/usr/bin/createrepo_c' - else: - createrepo = 'createrepo' - - os.chdir(output) - subprocess.check_call([createrepo, '-g', 'comps.xml', '.']) if __name__ == "__main__": sys.exit(main()) diff --git a/sw-patch/cgcs-patch/cgcs_patch/patch_controller.py b/sw-patch/cgcs-patch/cgcs_patch/patch_controller.py index 71f86019b..1be1f8811 100644 --- a/sw-patch/cgcs-patch/cgcs_patch/patch_controller.py +++ b/sw-patch/cgcs-patch/cgcs_patch/patch_controller.py @@ -1,5 +1,5 @@ """ -Copyright (c) 2014-2019 Wind River Systems, Inc. +Copyright (c) 2014-2022 Wind River Systems, Inc. SPDX-License-Identifier: Apache-2.0 @@ -27,10 +27,7 @@ from cgcs_patch.patch_functions import BasePackageData from cgcs_patch.patch_functions import avail_dir from cgcs_patch.patch_functions import applied_dir from cgcs_patch.patch_functions import committed_dir -from cgcs_patch.patch_functions import contentCompare from cgcs_patch.patch_functions import PatchFile -from cgcs_patch.patch_functions import parse_rpm_filename -from cgcs_patch.patch_functions import parse_pkgver from cgcs_patch.patch_functions import package_dir from cgcs_patch.patch_functions import repo_dir from cgcs_patch.patch_functions import semantics_dir @@ -767,9 +764,7 @@ class PatchController(PatchService): continue for pkg in list(self.hosts[ip].installed): - for patch_id in list(self.patch_data.content_versions): - if pkg not in self.patch_data.content_versions[patch_id]: - continue + for patch_id in list(self.patch_data.contents): if patch_id not in self.patch_data.metadata: LOG.error("Patch data missing for %s", patch_id) @@ -786,19 +781,11 @@ class PatchController(PatchService): # Ignore epoch installed_ver = installed_ver.split(':')[1] - patch_ver = self.patch_data.content_versions[patch_id][pkg] - if ":" in patch_ver: - # Ignore epoch - patch_ver = patch_ver.split(':')[1] - - rc = contentCompare(parse_pkgver(installed_ver), - parse_pkgver(patch_ver)) - if self.patch_data.metadata[patch_id]["repostate"] == constants.AVAILABLE: # The RPM is not expected to be installed. # If the installed version is the same or higher, # this patch is in a Partial-Remove state - if rc >= 0 or patch_id in self.interim_state: + if patch_id in self.interim_state: self.patch_data.metadata[patch_id]["patchstate"] = constants.PARTIAL_REMOVE if self.patch_data.metadata[patch_id].get("reboot_required") != "N": self.allow_insvc_patching = False @@ -807,7 +794,7 @@ class PatchController(PatchService): # The RPM is expected to be installed. # If the installed version is the lower, # this patch is in a Partial-Apply state - if rc == -1 or patch_id in self.interim_state: + if patch_id in self.interim_state: self.patch_data.metadata[patch_id]["patchstate"] = constants.PARTIAL_APPLY if self.patch_data.metadata[patch_id].get("reboot_required") != "N": self.allow_insvc_patching = False @@ -821,8 +808,8 @@ class PatchController(PatchService): # Check the to_remove list for pkg in self.hosts[ip].to_remove: - for patch_id in list(self.patch_data.content_versions): - if pkg not in self.patch_data.content_versions[patch_id]: + for patch_id in list(self.patch_data.contents): + if pkg not in self.patch_data.contents[patch_id]: continue if patch_id not in self.patch_data.metadata: @@ -845,8 +832,8 @@ class PatchController(PatchService): # Check the missing_pkgs list for pkg in self.hosts[ip].missing_pkgs: - for patch_id in list(self.patch_data.content_versions): - if pkg not in self.patch_data.content_versions[patch_id]: + for patch_id in list(self.patch_data.contents): + if pkg not in self.patch_data.contents[patch_id]: continue if patch_id not in self.patch_data.metadata: @@ -972,7 +959,6 @@ class PatchController(PatchService): metadata_dir=mdir, metadata_only=True, existing_content=self.patch_data.contents[patch_id], - allpatches=self.patch_data, base_pkgdata=self.base_pkgdata) self.patch_data.update_patch(thispatch) msg = "%s is already imported. Updated metadata only" % patch_id @@ -1007,11 +993,10 @@ class PatchController(PatchService): try: thispatch = PatchFile.extract_patch(patch, metadata_dir=avail_dir, - allpatches=self.patch_data, base_pkgdata=self.base_pkgdata) msg_info += "%s is now available\n" % patch_id - self.patch_data.add_patch(patch_id, thispatch) + self.patch_data.add_patch(thispatch) self.patch_data.metadata[patch_id]["repostate"] = constants.AVAILABLE if len(self.hosts) > 0: @@ -1131,51 +1116,6 @@ class PatchController(PatchService): msg_info += msg + "\n" continue - # To allow for easy cleanup, we're going to first iterate - # through the content list to determine where to copy the file. - # As a second step, we'll go through the list and copy each file. - # If there are problems querying the content, none will be copied. - content_dict = {} - patch_sw_version = self.patch_data.metadata[patch_id]["sw_version"] - for contentname in self.patch_data.contents[patch_id]: - # the log can be debug or removed altogether once code is working - msg = "OSTREE applying %s " % contentname - LOG.info(msg) - contentfile = self.get_store_filename(patch_sw_version, contentname) - if not os.path.isfile(contentfile): - msg = "Could not find content file: %s" % contentfile - LOG.error(msg) - raise ContentFail(msg) - - # todo: should 'repo' be replaced with something ostree related - repo_filename = self.get_repo_filename(patch_sw_version, contentname) - if repo_filename is None: - msg = "Failed to determine repo path for %s" % contentfile - LOG.exception(msg) - raise ContentFail(msg) - - repo_pkg_dir = os.path.dirname(repo_filename) - if not os.path.exists(repo_pkg_dir): - os.makedirs(repo_pkg_dir) - content_dict[contentfile] = repo_filename - - # Copy the Content. If a failure occurs, clean up copied files. - copied = [] - for contentfile, repo_filename in content_dict.items(): - LOG.info("Copy %s to %s", contentfile, repo_filename) - try: - shutil.copy(contentfile, repo_filename) - copied.append(repo_filename) - except IOError: - msg = "Failed to copy %s" % contentfile - LOG.exception(msg) - # Clean up files - for filename in copied: - LOG.info("Cleaning up %s", filename) - os.remove(filename) - - raise ContentFail(msg) - try: # Move the patching metadata from avail to applied dir shutil.move("%s/%s-metadata.xml" % (avail_dir, patch_id), @@ -1516,9 +1456,6 @@ class PatchController(PatchService): LOG.info(msg) return dict(info=msg_info, warning=msg_warning, error=msg_error) - # Generate the groups xml - self.patch_data.gen_release_groups_xml(release) - # Create the repo try: # todo(jcasteli) determine if ostree change needs a createrepo equivalent @@ -1933,60 +1870,6 @@ class PatchController(PatchService): if patch_sw_version not in cleanup: cleanup[patch_sw_version] = {} - for rpmname in self.patch_data.contents[patch_id]: - try: - pkgname, arch, pkgver = parse_rpm_filename(rpmname) - except ValueError as e: - self.patch_data_lock.release() - raise e - - if pkgname not in keep[patch_sw_version]: - keep[patch_sw_version][pkgname] = {arch: pkgver} - continue - elif arch not in keep[patch_sw_version][pkgname]: - keep[patch_sw_version][pkgname][arch] = pkgver - continue - - # Compare versions - keep_pkgver = keep[patch_sw_version][pkgname][arch] - if pkgver > keep_pkgver: - if pkgname not in cleanup[patch_sw_version]: - cleanup[patch_sw_version][pkgname] = {arch: [keep_pkgver]} - elif arch not in cleanup[patch_sw_version][pkgname]: - cleanup[patch_sw_version][pkgname][arch] = [keep_pkgver] - else: - cleanup[patch_sw_version][pkgname][arch].append(keep_pkgver) - - # Find the rpmname - keep_rpmname = keep_pkgver.generate_rpm_filename(pkgname, arch) - - store_filename = self.get_store_filename(patch_sw_version, keep_rpmname) - if store_filename is not None and os.path.exists(store_filename): - cleanup_files.add(store_filename) - - repo_filename = self.get_repo_filename(patch_sw_version, keep_rpmname) - if repo_filename is not None and os.path.exists(repo_filename): - cleanup_files.add(repo_filename) - - # Keep the new pkgver - keep[patch_sw_version][pkgname][arch] = pkgver - else: - # Put this pkg in the cleanup list - if pkgname not in cleanup[patch_sw_version]: - cleanup[patch_sw_version][pkgname] = {arch: [pkgver]} - elif arch not in cleanup[patch_sw_version][pkgname]: - cleanup[patch_sw_version][pkgname][arch] = [pkgver] - else: - cleanup[patch_sw_version][pkgname][arch].append(pkgver) - - store_filename = self.get_store_filename(patch_sw_version, rpmname) - if store_filename is not None and os.path.exists(store_filename): - cleanup_files.add(store_filename) - - repo_filename = self.get_repo_filename(patch_sw_version, rpmname) - if repo_filename is not None and os.path.exists(repo_filename): - cleanup_files.add(repo_filename) - self.patch_data_lock.release() # Calculate disk space @@ -2024,8 +1907,6 @@ class PatchController(PatchService): raise MetadataFail(msg) # OSTREE: this repo update code needs to be re-examined - # Update the repo - self.patch_data.gen_groups_xml() for ver, rdir in repo_dir.items(): try: # todo(jcasteli) determine if ostree change needs additional actions diff --git a/sw-patch/cgcs-patch/cgcs_patch/patch_functions.py b/sw-patch/cgcs-patch/cgcs_patch/patch_functions.py index 2270214e4..b79b4a94e 100644 --- a/sw-patch/cgcs-patch/cgcs_patch/patch_functions.py +++ b/sw-patch/cgcs-patch/cgcs_patch/patch_functions.py @@ -1,5 +1,5 @@ """ -Copyright (c) 2014-2019 Wind River Systems, Inc. +Copyright (c) 2014-2022 Wind River Systems, Inc. SPDX-License-Identifier: Apache-2.0 @@ -157,55 +157,6 @@ def write_xml_file(top, outfile.write(minidom.parseString(rough_xml).toprettyxml(indent=" ")) -def parse_rpm_filename(filename): - - # Drop the extension - basename = os.path.splitext(os.path.basename(filename))[0] - - # RPM name format is: - # [:]--. - # - pattern = re.compile(r'((([^:]):)?)(.*)-([^-]+)-(.*)\.([^\.]*)$') - - m = pattern.match(basename) - - if m is None: - raise ValueError("Filename does not match expected RPM format: %s" % basename) - - epoch = m.group(3) - pkgname = m.group(4) - version = m.group(5) - release = m.group(6) - arch = m.group(7) - - return (pkgname, arch, PackageVersion(epoch, version, release)) - - -def parse_pkgver(pkgver): - # Version format is: - # [:]- - # - pattern = re.compile(r'((([^:]):)?)([^-]+)((-(.*))?)$') - - m = pattern.match(pkgver) - - if m is None: - raise ValueError("Package version does not match expected format: %s" % pkgver) - - epoch = m.group(3) - version = m.group(4) - release = m.group(7) - - return (epoch, version, release) - - -# OSTREE: this method may be removed or revisited -# based on comparing SHAs and dependencies -def contentCompare(_list1, _list2): - LOG.info("OSTREE: DEV MODE. contentCompare always returns zero") - return 0 - - def get_release_from_patch(patchfile): rel = "" try: @@ -224,87 +175,6 @@ def get_release_from_patch(patchfile): return rel -class PackageVersion(object): - """ - The PackageVersion class provides a structure for RPM version information, - along with suport for comparison operators. - """ - def __init__(self, epoch, version, release): - self.epoch = epoch - self.version = version - self.release = release - - def __le__(self, other): - """ - This function is called by comparison operators to compare - two versions. The contentCompare() function takes two versions, - specified in a list structure, and returns -1, 0, or 1. - """ - out = contentCompare((self.epoch, self.version, self.release), - (other.epoch, other.version, other.release)) - if out == 1: - return False - return True - - def __eq__(self, other): - out = contentCompare((self.epoch, self.version, self.release), - (other.epoch, other.version, other.release)) - if out == 0: - return True - return False - - def __ne__(self, other): - out = contentCompare((self.epoch, self.version, self.release), - (other.epoch, other.version, other.release)) - if out == 0: - return False - return True - - def __gt__(self, other): - out = contentCompare((self.epoch, self.version, self.release), - (other.epoch, other.version, other.release)) - if out == 1: - return True - return False - - def __lt__(self, other): - out = contentCompare((self.epoch, self.version, self.release), - (other.epoch, other.version, other.release)) - if out == -1: - return True - return False - - def __ge__(self, other): - out = contentCompare((self.epoch, self.version, self.release), - (other.epoch, other.version, other.release)) - if out == -1: - return False - return True - - def __str__(self): - """ - This function is called by str() and print to compute the - informal string representation of a PackageVersion object. - """ - prefix = "" - if self.epoch is not None and self.epoch != '': - # Prefix the version with epoch, if specified - prefix = "%s:" % self.epoch - - return "%s%s-%s" % (prefix, self.version, self.release) - - def __hash__(self): - return hash(self.__str__()) - - def generate_rpm_filename(self, pkgname, arch): - prefix = "" - if self.epoch is not None and self.epoch != '': - # Prefix the version with epoch, if specified - prefix = "%s:" % self.epoch - - return "%s%s-%s-%s.%s.rpm" % (prefix, pkgname, self.version, self.release, arch) - - class BasePackageData(object): """ Information about the base package data provided by the load @@ -331,17 +201,6 @@ class BasePackageData(object): continue self.pkgs[sw_rel] = {} - for _root, _dirs, files in os.walk("%s/Packages" % reldir): # pylint: disable=unused-variable - for name in files: - if name.endswith(".rpm"): - try: - pkgname, arch, pkgver = parse_rpm_filename(name) - except ValueError as e: - raise e - - if pkgname not in self.pkgs[sw_rel]: - self.pkgs[sw_rel][pkgname] = {} - self.pkgs[sw_rel][pkgname][arch] = pkgver # Clean up deleted data for sw_rel in self.pkgs: @@ -365,19 +224,6 @@ class PatchData(object): Aggregated patch data """ def __init__(self): - # - # The groups dict provides information about targetted (new) packages, - # identifying the software group in which to include the package. - # This allows the patch agent to identify new packages to install - # (or erase) as appropriate. - # This dict is nested as follows: - # [ patch_sw_version ] - Release associated with the patch - # [ group/ptype ] - Group (personality) in which the pkg belongs - # [ patch_id ] - # [ package ] - # - self.groups = {} - # # The metadata dict stores all metadata associated with a patch. # This dict is keyed on patch_id, with metadata for each patch stored @@ -391,61 +237,10 @@ class PatchData(object): # self.contents = {} - # - # The content_versions dict provides a simple list of packages and their - # versions for each patch, used by the patch controller in determining - # patch states. - # content_versions[patch_id][pkgname] = "%s-%s" % (pkgver.version, pkgver.release) - # - self.content_versions = {} - - # - # The package_versions dict provides a mapping of packages to the patch_id, - # including the package arch. - # [ patch_sw_version ] - # [ pkgname ] - # [ arch ] - # [ pkgver ] - # -> patch_id - self.package_versions = {} - - # - # The semantics dict stores the lists of semantic actions provided by each patch, - # indexed by patch_id. - # - self.semantics = {} - - def add_patch(self, patch_id, new_patch): + def add_patch(self, new_patch): # We can just use "update" on these dicts because they are indexed by patch_id self.metadata.update(new_patch.metadata) self.contents.update(new_patch.contents) - self.content_versions.update(new_patch.content_versions) - self.semantics.update(new_patch.semantics) - - # Need to recursively update package_version and keys dicts - for patch_sw_version in list(new_patch.package_versions): - if patch_sw_version not in self.package_versions: - self.package_versions[patch_sw_version] = {} - for pkgname in list(new_patch.package_versions[patch_sw_version]): - if pkgname not in self.package_versions[patch_sw_version]: - self.package_versions[patch_sw_version][pkgname] = {} - for arch in list(new_patch.package_versions[patch_sw_version][pkgname]): - if arch not in self.package_versions[patch_sw_version][pkgname]: - self.package_versions[patch_sw_version][pkgname][arch] = {} - for pkgver in list(new_patch.package_versions[patch_sw_version][pkgname][arch]): - self.package_versions[patch_sw_version][pkgname][arch][pkgver] = patch_id - - for patch_sw_version in list(new_patch.groups): - if patch_sw_version not in self.groups: - self.groups[patch_sw_version] = {} - for ptype in list(new_patch.groups[patch_sw_version]): - if ptype not in self.groups[patch_sw_version]: - self.groups[patch_sw_version][ptype] = {} - for patch_id in list(new_patch.groups[patch_sw_version][ptype]): - if patch_id not in self.groups[patch_sw_version][ptype]: - self.groups[patch_sw_version][ptype][patch_id] = {} - self.groups[patch_sw_version][ptype][patch_id].update( - new_patch.groups[patch_sw_version][ptype][patch_id]) def update_patch(self, updated_patch): for patch_id in list(updated_patch.metadata): @@ -455,27 +250,7 @@ class PatchData(object): self.metadata[patch_id]['repostate'] = cur_repostate def delete_patch(self, patch_id): - for patch_sw_version in list(self.package_versions): - for pkgname in list(self.package_versions[patch_sw_version]): - for arch in list(self.package_versions[patch_sw_version][pkgname]): - for pkgver in list(self.package_versions[patch_sw_version][pkgname][arch]): - if self.package_versions[patch_sw_version][pkgname][arch][pkgver] == patch_id: - del self.package_versions[patch_sw_version][pkgname][arch][pkgver] - if len(self.package_versions[patch_sw_version][pkgname][arch]) == 0: - del self.package_versions[patch_sw_version][pkgname][arch] - if len(self.package_versions[patch_sw_version][pkgname]) == 0: - del self.package_versions[patch_sw_version][pkgname] - if len(self.package_versions[patch_sw_version]) == 0: - del self.package_versions[patch_sw_version] - - for patch_sw_version in list(self.groups): - for ptype in list(self.groups[patch_sw_version]): - if patch_id in self.groups[patch_sw_version][ptype]: - del self.groups[patch_sw_version][ptype][patch_id] - - del self.content_versions[patch_id] del self.contents[patch_id] - del self.semantics[patch_id] del self.metadata[patch_id] @staticmethod @@ -541,13 +316,6 @@ class PatchData(object): # Dev # # - # - # pkgA - # pkgB - # - # - # pkgB - # # # @@ -590,67 +358,27 @@ class PatchData(object): package_dir[patch_sw_version] = "%s/%s" % (root_package_dir, patch_sw_version) repo_dir[patch_sw_version] = "%s/rel-%s" % (repo_root_dir, patch_sw_version) - # Specifying personality for given packages is optional, - # intended to allow a patch to include a new package. - # For each configured personality type, create a software group. - for personality in root.findall("personality"): - ptype = personality.attrib["type"] - tag = "personality-%s" % ptype - self.metadata[patch_id][tag] = list() - for pkg in personality.findall("package"): - self.metadata[patch_id][tag].append(pkg.text) - if patch_sw_version not in self.groups: - self.groups[patch_sw_version] = {} - if ptype not in self.groups[patch_sw_version]: - self.groups[patch_sw_version][ptype] = {} - if patch_id not in self.groups[patch_sw_version][ptype]: - self.groups[patch_sw_version][ptype][patch_id] = {} - self.groups[patch_sw_version][ptype][patch_id][pkg.text] = True - self.metadata[patch_id]["requires"] = [] for req in root.findall("requires"): for req_patch in req.findall("req_patch_id"): self.metadata[patch_id]["requires"].append(req_patch.text) - self.contents[patch_id] = list() - self.content_versions[patch_id] = {} + self.contents[patch_id] = {} - for content in root.findall("contents"): - for rpmname in content.findall("rpm"): - try: - pkgname, arch, pkgver = parse_rpm_filename(rpmname.text) - except ValueError as e: - LOG.exception(e) - return None - - self.contents[patch_id].append(rpmname.text) - self.content_versions[patch_id][pkgname] = "%s-%s" % (pkgver.version, pkgver.release) - - if patch_sw_version not in self.package_versions: - self.package_versions[patch_sw_version] = {} - if pkgname not in self.package_versions[patch_sw_version]: - self.package_versions[patch_sw_version][pkgname] = {} - if arch not in self.package_versions[patch_sw_version][pkgname]: - self.package_versions[patch_sw_version][pkgname][arch] = {} - - self.package_versions[patch_sw_version][pkgname][arch][pkgver] = patch_id - - self.semantics[patch_id] = list() - for semantics in root.findall("semantics"): - for action in semantics.findall("action"): - self.semantics[patch_id].append(action.text) + for content in root.findall("contents/ostree"): + self.contents[patch_id]["number_of_commits"] = content.findall("number_of_commits")[0].text + self.contents[patch_id]["base"] = {} + self.contents[patch_id]["base"]["commit"] = content.findall("base/commit")[0].text + self.contents[patch_id]["base"]["checksum"] = content.findall("base/checksum")[0].text + for i in range(int(self.contents[patch_id]["number_of_commits"])): + self.contents[patch_id]["commit%s" % (i + 1)] = {} + self.contents[patch_id]["commit%s" % (i + 1)]["commit"] = \ + content.findall("commit%s/commit" % (i + 1))[0].text + self.contents[patch_id]["commit%s" % (i + 1)]["checksum"] = \ + content.findall("commit%s/checksum" % (i + 1))[0].text return patch_id - def find_patch_with_pkgver(self, sw_ver, pkgname, arch, pkgver): - if sw_ver not in self.package_versions or \ - pkgname not in self.package_versions[sw_ver] or \ - arch not in self.package_versions[sw_ver][pkgname] or \ - pkgver not in self.package_versions[sw_ver][pkgname][arch]: - return None - - return self.package_versions[sw_ver][pkgname][arch][pkgver] - def load_all_metadata(self, loaddir, repostate=None): @@ -668,54 +396,6 @@ class PatchData(object): self.load_all_metadata(avail_dir, repostate=constants.AVAILABLE) self.load_all_metadata(committed_dir, repostate=constants.COMMITTED) - def gen_release_groups_xml(self, sw_version, output_dir=None): - """ - Generate the groups configuration file for the patching repo - """ - if output_dir is None: - output_dir = repo_dir[sw_version] - - if not os.path.exists(output_dir): - os.makedirs(output_dir) - - fname = "%s/comps.xml" % output_dir - top = ElementTree.Element('comps') - if sw_version in self.groups: - for groupname in sorted(list(self.groups[sw_version])): - if self.groups[sw_version][groupname]: - group = ElementTree.SubElement(top, 'group') - - add_text_tag_to_xml(group, 'id', - "updates-%s" % groupname) - add_text_tag_to_xml(group, 'default', - "false") - add_text_tag_to_xml(group, 'uservisible', - "true") - add_text_tag_to_xml(group, 'display_order', - "1024") - add_text_tag_to_xml(group, 'name', - "updates-%s" % groupname) - add_text_tag_to_xml(group, 'description', - "Patches for %s" % groupname) - - package_element = ElementTree.SubElement(group, - 'packagelist') - - for patch_id in sorted(self.groups[sw_version][groupname]): - if self.metadata[patch_id]["repostate"] == constants.APPLIED \ - or self.metadata[patch_id]["repostate"] == constants.COMMITTED: - for pkg in sorted(self.groups[sw_version][groupname][patch_id]): - tag = ElementTree.SubElement(package_element, - 'packagereq', - type="mandatory") - tag.text = pkg - - write_xml_file(top, fname) - - def gen_groups_xml(self): - for ver in repo_dir: - self.gen_release_groups_xml(ver) - def query_line(self, patch_id, index): @@ -748,23 +428,7 @@ class PatchMetadata(object): self.reboot_required = None self.apply_active_release_only = None self.requires = [] - self.groups = {} self.contents = {} - self.semantics = [] - - def add_package(self, - groupname, - pkg): - """ - Add a package to a particular group - :param groupname: Yum software group, eg. "controller" - :param pkg: Name of the package - :return: - """ - if groupname not in self.groups: - self.groups[groupname] = {} - - self.groups[groupname][pkg] = True def add_rpm(self, fname): @@ -776,15 +440,6 @@ class PatchMetadata(object): rpmname = os.path.basename(fname) self.contents[rpmname] = True - def add_semantic(self, - action): - """ - Add a semantic check to the patch - :param action: semantic action - :return: - """ - self.semantics.append(action) - def gen_xml(self, fname="metadata.xml"): """ @@ -815,15 +470,6 @@ class PatchMetadata(object): add_text_tag_to_xml(top, 'apply_active_release_only', self.apply_active_release_only) - for groupname in sorted(list(self.groups)): - if self.groups[groupname]: - group = ElementTree.SubElement(top, - 'personality', - type=groupname) - - for pkg in sorted(self.groups[groupname]): - add_text_tag_to_xml(group, 'package', pkg) - content = ElementTree.SubElement(top, 'contents') for rpmname in sorted(list(self.contents)): add_text_tag_to_xml(content, 'rpm', rpmname) @@ -832,10 +478,6 @@ class PatchMetadata(object): for req_patch in sorted(self.requires): add_text_tag_to_xml(req, 'req_patch_id', req_patch) - semantics = ElementTree.SubElement(top, 'semantics') - for action in sorted(self.semantics): - add_text_tag_to_xml(semantics, 'action', action) - write_xml_file(top, fname) @@ -846,11 +488,9 @@ class PatchFile(object): def __init__(self): self.meta = PatchMetadata() self.rpmlist = {} - self.semantics = {} def add_rpm(self, - fname, - personality=None): + fname): """ Add an RPM to the patch :param fname: Path to RPM @@ -865,44 +505,12 @@ class PatchFile(object): # Add the RPM to the patch self.rpmlist[os.path.abspath(fname)] = True - if personality is not None: - # Get the package name from the RPM itself, - # and add it to the appropriate group(s) - pkgname = subprocess.check_output(["rpm", - "-qp", - "--queryformat", - "%{NAME}", - "--nosignature", - fname]) - if isinstance(personality, list): - for p in personality: - self.meta.add_package(p, pkgname) - elif isinstance(personality, str): - self.meta.add_package(personality, pkgname) - - def add_semantic(self, - action, - fname): - """ - Add a semantic check to the patch - :param action: Semantic check type - :param fname: Path to semantic check - :return: - """ - # Add the semantic to the metadata - self.meta.add_semantic(action) - - self.semantics[action] = os.path.abspath(fname) - def gen_patch(self, outdir): """ Generate the patch file, named PATCHID.patch :param outdir: Output directory for the patch :return: """ - if self.meta.sw_version is None or self.meta.sw_version == '': - raise MetadataFail("The release version must be specified in the sw_version field") - if not self.rpmlist: raise MetadataFail("Cannot generate empty patch") @@ -936,16 +544,6 @@ class PatchFile(object): tar.add(os.path.basename(rpmfile)) tar.close() - # Copy semantics to tmpdir, if any - if len(self.semantics) > 0: - tar = tarfile.open("semantics.tar", "w") - for action in list(self.semantics): - os.mkdir(action, 0o755) - sname = os.path.join(action, self.meta.id) - shutil.copy(self.semantics[action], sname) - tar.add(sname) - tar.close() - # Generate the metadata xml file self.meta.gen_xml("metadata.xml") @@ -1014,7 +612,7 @@ class PatchFile(object): raise SystemExit(e.returncode) @staticmethod - def read_patch(path, metadata_only=False, cert_type=None): + def read_patch(path, cert_type=None): # We want to enable signature checking by default # Note: cert_type=None is required if we are to enforce 'no dev patches on a formal load' rule. @@ -1073,14 +671,6 @@ class PatchFile(object): tar = tarfile.open("metadata.tar") tar.extractall() - if not metadata_only: - tar = tarfile.open("software.tar") - tar.extractall() - - if os.path.exists("semantics.tar"): - tar = tarfile.open("semantics.tar") - tar.extractall() - @staticmethod def query_patch(patch, field=None): @@ -1102,7 +692,7 @@ class PatchFile(object): # Need to determine the cert_type for cert_type_str in cert_type_all: try: - PatchFile.read_patch(abs_patch, metadata_only=True, cert_type=[cert_type_str]) + PatchFile.read_patch(abs_patch, cert_type=[cert_type_str]) except PatchValidationFailure: pass else: @@ -1116,7 +706,7 @@ class PatchFile(object): # We can't omit cert_type, or pass None, because that will trigger the code # path used by installed product, in which dev keys are not accepted unless # a magic file exists. - PatchFile.read_patch(abs_patch, metadata_only=True, cert_type=cert_type_all) + PatchFile.read_patch(abs_patch, cert_type=cert_type_all) thispatch = PatchData() patch_id = thispatch.parse_metadata("metadata.xml") @@ -1174,7 +764,7 @@ class PatchFile(object): meta_data = PatchFile.query_patch(abs_patch) if 'cert' in meta_data: cert_type = meta_data['cert'] - PatchFile.read_patch(abs_patch, metadata_only=True, cert_type=cert_type) + PatchFile.read_patch(abs_patch, cert_type=cert_type) PatchData.modify_metadata_text("metadata.xml", key, value) PatchFile.write_patch(new_abs_patch, cert_type=cert_type) os.rename(new_abs_patch, abs_patch) @@ -1204,7 +794,6 @@ class PatchFile(object): metadata_dir=avail_dir, metadata_only=False, existing_content=None, - allpatches=None, base_pkgdata=None): """ Extract the metadata and patch contents @@ -1228,7 +817,7 @@ class PatchFile(object): try: # Open the patch file and extract the contents to the tmpdir - PatchFile.read_patch(abs_patch, metadata_only) + PatchFile.read_patch(abs_patch) thispatch = PatchData() patch_id = thispatch.parse_metadata("metadata.xml") @@ -1248,38 +837,13 @@ class PatchFile(object): LOG.exception(msg) raise PatchValidationFailure(msg) - for rpmname in thispatch.contents[patch_id]: - pkgname, arch, pkgver = parse_rpm_filename(rpmname) - base_pkgver = base_pkgdata.find_version(patch_sw_version, pkgname, arch) - if base_pkgver is not None: - # Compare the patch RPM's version against the base - if pkgver <= base_pkgver: - msg = "RPM %s in patch %s must be higher version than original (%s)" % \ - (rpmname, patch_id, base_pkgver) - LOG.exception(msg) - raise PatchValidationFailure(msg) - - if allpatches is not None: - # Compare the patch RPM's version against other patches - other = allpatches.find_patch_with_pkgver(patch_sw_version, pkgname, arch, pkgver) - if other is not None: - msg = "Patch %s contains rpm %s, which is already provided by patch %s" % \ - (patch_id, rpmname, other) - LOG.exception(msg) - raise PatchValidationFailure(msg) - if metadata_only: # This is a re-import. Ensure the content lines up if existing_content is None \ - or len(existing_content) != len(thispatch.contents[patch_id]): + or existing_content != thispatch.contents[patch_id]: msg = "Contents of re-imported patch do not match" LOG.exception(msg) raise PatchMismatchFailure(msg) - for rpmname in existing_content: - if rpmname not in thispatch.contents[patch_id]: - msg = "Contents of re-imported patch do not match" - LOG.exception(msg) - raise PatchMismatchFailure(msg) shutil.move("metadata.xml", "%s/%s-metadata.xml" % (abs_metadata_dir, patch_id)) @@ -1292,18 +856,6 @@ class PatchFile(object): os.makedirs(rpm_dir) shutil.move(rpmname, "%s/" % rpm_dir) - for action in constants.SEMANTIC_ACTIONS: - action_file = os.path.join(action, patch_id) - if not os.path.exists(action_file): - continue - - action_dir = os.path.join(semantics_dir, action) - if not os.path.exists(action_dir): - os.makedirs(action_dir) - - os.chmod(action_file, 0o544) - shutil.move(action_file, action_dir) - except PatchValidationFailure as e: raise e except PatchMismatchFailure as e: @@ -1415,25 +967,6 @@ def patch_build(): pf.meta.install_instructions = arg elif opt == "--req": pf.meta.requires.append(arg) - elif opt == "--all-nodes": - for p in ("controller", - "worker", - "worker-lowlatency", - "storage", - "controller-worker", - "controller-worker-lowlatency"): - pf.add_rpm(arg, personality=p) - elif opt in ("--controller", - "--worker", - "--worker-lowlatency", - "--storage", - "--controller-worker", - "--controller-worker-lowlatency"): - pf.add_rpm(arg, personality=opt[2:]) - elif opt == "--pre-apply": - pf.add_semantic(constants.SEMANTIC_PREAPPLY, arg) - elif opt == "--pre-remove": - pf.add_semantic(constants.SEMANTIC_PREREMOVE, arg) elif opt == "--apply-active-release-only": pf.meta.apply_active_release_only = "Y" diff --git a/sw-patch/cgcs-patch/cgcs_patch/tests/test_patch_utils.py b/sw-patch/cgcs-patch/cgcs_patch/tests/test_patch_utils.py index 653c65a06..393e3dc83 100644 --- a/sw-patch/cgcs-patch/cgcs_patch/tests/test_patch_utils.py +++ b/sw-patch/cgcs-patch/cgcs_patch/tests/test_patch_utils.py @@ -1,7 +1,7 @@ # # SPDX-License-Identifier: Apache-2.0 # -# Copyright (c) 2019 Wind River Systems, Inc. +# Copyright (c) 2019-2022 Wind River Systems, Inc. # import mock @@ -131,16 +131,3 @@ class CgcsPatchUtilsTestCase(testtools.TestCase): result = cgcs_patch.utils.ip_to_versioned_localhost(ip) self.assertEqual(expected_result, result) - - def test_parse_pkgver(self): - versions = { - '0:1.2.3-r4': ('0', '1.2.3', 'r4'), - '4.3.2-1': (None, '4.3.2', '1'), - '8.1.4': (None, '8.1.4', None), - '5:7.5.3': ('5', '7.5.3', None), - 'This is a weird version string': (None, 'This is a weird version string', None), - } - - for ver, expected in versions.items(): - result = cgcs_patch.patch_functions.parse_pkgver(ver) - self.assertEqual(result, expected)