def compute_actual_version(self): """ After packages are installed, determine what the new actual version is, in order to save it. """ Logger.info( "Attempting to determine actual version with build number.") Logger.info("Old versions: {0}".format(self.old_versions)) new_versions = get_hdp_versions() Logger.info("New versions: {0}".format(new_versions)) deltas = set(new_versions) - set(self.old_versions) Logger.info("Deltas: {0}".format(deltas)) # Get HDP version without build number normalized_repo_version = self.repository_version.split('-')[0] if 1 == len(deltas): self.actual_version = next(iter(deltas)).strip() self.structured_output['actual_version'] = self.actual_version self.put_structured_out(self.structured_output) write_actual_version_to_history_file(normalized_repo_version, self.actual_version) else: Logger.info( "Cannot determine a new actual version installed by using the delta method." ) # If the first install attempt does a partial install and is unable to report this to the server, # then a subsequent attempt will report an empty delta. For this reason, it is important to search the # repo version history file to determine if we previously did write an actual_version. self.actual_version = read_actual_version_from_history_file( normalized_repo_version) if self.actual_version is not None: self.actual_version = self.actual_version.strip() self.structured_output['actual_version'] = self.actual_version self.put_structured_out(self.structured_output) Logger.info( "Found actual version {0} by parsing file {1}".format( self.actual_version, REPO_VERSION_HISTORY_FILE)) elif self.repo_version_with_build_number is None: # It's likely that this host does not have any Stack Components installed, so only contains AMS. # So just use repo version value provided by server (we already put it to structured output) if not os.path.exists(self.stack_root_folder): # Special case when this host does not contain any HDP components, but still contains other components like AMS. msg = "Could not determine actual version. This stack's root directory ({0}) is not present on this host, so this host does not contain any versionable components. " \ "Therefore, ignore this host and allow other hosts to report the correct repository version.".format(self.stack_root_folder) Logger.info(msg) else: msg = "Could not determine actual version. This stack's root directory ({0}) exists but was not able to determine the actual repository version installed. " \ "Try reinstalling packages again.".format(self.stack_root_folder) raise Fail(msg)
def find_best_fit_version(self, versions, repo_version): """ Given a list of installed versions and a repo version, search for a version that best fits the repo version If the repo version is found in the list of installed versions, return the repo version itself. If the repo version is not found in the list of installed versions normalize the repo version and use the REPO_VERSION_HISTORY_FILE file to search the list. :param versions: List of versions installed :param repo_version: Repo version to search :return: Matching version, None if no match was found. """ if versions is None or repo_version is None: return None build_num_match = re.search("[\d\.]+-\d+", repo_version) if build_num_match and repo_version in versions: # If repo version has build number and is found in the list of versions, return it as the matching version Logger.info( "Best Fit Version: Resolved from repo version with valid build number: {0}" .format(repo_version)) return repo_version # Get version without build number normalized_repo_version = repo_version.split('-')[0] # Find all versions that match the normalized repo version match_versions = filter( lambda x: x.startswith(normalized_repo_version), versions) if match_versions: if len(match_versions) == 1: # Resolved without conflicts Logger.info( "Best Fit Version: Resolved from normalized repo version without conflicts: {0}" .format(match_versions[0])) return match_versions[0] # Resolve conflicts using REPO_VERSION_HISTORY_FILE history_version = read_actual_version_from_history_file( normalized_repo_version) # Validate history version retrieved is valid if history_version in match_versions: Logger.info( "Best Fit Version: Resolved from normalized repo version using {0}: {1}" .format(REPO_VERSION_HISTORY_FILE, history_version)) return history_version # No matching version return None
def compute_actual_version(self): """ After packages are installed, determine what the new actual version is, in order to save it. """ Logger.info( "Attempting to determine actual version with build number.") Logger.info("Old versions: {0}".format(self.old_versions)) new_versions = get_hdp_versions() Logger.info("New versions: {0}".format(new_versions)) deltas = set(new_versions) - set(self.old_versions) Logger.info("Deltas: {0}".format(deltas)) # Get HDP version without build number normalized_repo_version = self.repository_version.split('-')[0] if 1 == len(deltas): self.actual_version = next(iter(deltas)).strip() self.structured_output['actual_version'] = self.actual_version self.put_structured_out(self.structured_output) write_actual_version_to_history_file(normalized_repo_version, self.actual_version) else: Logger.info( "Cannot determine a new actual version installed by using the delta method." ) # If the first install attempt does a partial install and is unable to report this to the server, # then a subsequent attempt will report an empty delta. For this reason, it is important to search the # repo version history file to determine if we previously did write an actual_version. self.actual_version = read_actual_version_from_history_file( normalized_repo_version) if self.actual_version is not None: self.actual_version = self.actual_version.strip() self.structured_output['actual_version'] = self.actual_version self.put_structured_out(self.structured_output) Logger.info( "Found actual version {0} by parsing file {1}".format( self.actual_version, REPO_VERSION_HISTORY_FILE)) elif self.repo_version_with_build_number is None: msg = "Could not determine actual version installed. Try reinstalling packages again." raise Fail(msg)
def find_best_fit_version(self, versions, repo_version): """ Given a list of installed versions and a repo version, search for a version that best fits the repo version If the repo version is found in the list of installed versions, return the repo version itself. If the repo version is not found in the list of installed versions normalize the repo version and use the REPO_VERSION_HISTORY_FILE file to search the list. :param versions: List of versions installed :param repo_version: Repo version to search :return: Matching version, None if no match was found. """ if versions is None or repo_version is None: return None build_num_match = re.search("[\d\.]+-\d+", repo_version) if build_num_match and repo_version in versions: # If repo version has build number and is found in the list of versions, return it as the matching version Logger.info("Best Fit Version: Resolved from repo version with valid build number: {0}".format(repo_version)) return repo_version # Get version without build number normalized_repo_version = repo_version.split('-')[0] # Find all versions that match the normalized repo version match_versions = filter(lambda x: x.startswith(normalized_repo_version), versions) if match_versions: if len(match_versions) == 1: # Resolved without conflicts Logger.info("Best Fit Version: Resolved from normalized repo version without conflicts: {0}".format(match_versions[0])) return match_versions[0] # Resolve conflicts using REPO_VERSION_HISTORY_FILE history_version = read_actual_version_from_history_file(normalized_repo_version) # Validate history version retrieved is valid if history_version in match_versions: Logger.info("Best Fit Version: Resolved from normalized repo version using {0}: {1}".format(REPO_VERSION_HISTORY_FILE, history_version)) return history_version # No matching version return None
def test_read_and_write_repo_version_history(self): f, filename = tempfile.mkstemp() try: # Check read of empty file repo_version_history.REPO_VERSION_HISTORY_FILE = filename repo_version_history.Logger = logging.getLogger() result = repo_version_history.read_actual_version_from_history_file('2.3.2.0') self.assertEquals(result, None) # Check read of single value repo_version_history.write_actual_version_to_history_file('2.3.2.0', '2.3.2.0-210') result = repo_version_history.read_actual_version_from_history_file('2.3.2.0') self.assertEquals(result, '2.3.2.0-210') # Check read after update repo_version_history.write_actual_version_to_history_file('2.3.2.0', '2.3.2.0-2716') result = repo_version_history.read_actual_version_from_history_file('2.3.2.0') self.assertEquals(result, '2.3.2.0-2716') # Check read after update repo_version_history.write_actual_version_to_history_file('2.3.2.0', '2.3.2.0-2758') result = repo_version_history.read_actual_version_from_history_file('2.3.2.0') self.assertEquals(result, '2.3.2.0-2758') # Check read after writing down version for another stack repo_version_history.write_actual_version_to_history_file('2.3.1.0', '2.3.1.0-27') result = repo_version_history.read_actual_version_from_history_file('2.3.1.0') self.assertEquals(result, '2.3.1.0-27') result = repo_version_history.read_actual_version_from_history_file('2.3.2.0') self.assertEquals(result, '2.3.2.0-2758') # Check read of another stack result = repo_version_history.read_actual_version_from_history_file('2.3.0.0') self.assertEquals(result, None) finally: os.unlink(filename)