OSPatching/patch/redhatPatching.py (119 lines of code) (raw):

#!/usr/bin/python # # Copyright 2014 Microsoft Corporation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import re from Utils.WAAgentUtil import waagent from AbstractPatching import AbstractPatching class redhatPatching(AbstractPatching): def __init__(self, hutil): super(redhatPatching,self).__init__(hutil) self.cron_restart_cmd = 'service crond restart' self.check_cmd = 'yum -q check-update' self.check_security_cmd = 'yum -q --security check-update' self.clean_cmd = 'yum clean packages' self.download_cmd = 'yum -q -y --downloadonly update' self.patch_cmd = 'yum -y update' self.status_cmd = 'yum -q info' self.pkg_query_cmd = 'repoquery -l' self.cache_dir = '/var/cache/yum/' def install(self): """ Install for dependencies. """ # For yum --downloadonly option waagent.Run('yum -y install yum-downloadonly', False) # For yum --security option retcode = waagent.Run('yum -y install yum-plugin-security') if retcode > 0: self.hutil.error("Failed to install yum-plugin-security") # For package-cleanup, needs-restarting, repoquery retcode = waagent.Run('yum -y install yum-utils') if retcode > 0: self.hutil.error("Failed to install yum-utils") # For lsof retcode = waagent.Run('yum -y install lsof') if retcode > 0: self.hutil.error("Failed to install lsof") # Install missing dependencies missing_dependency_list = self.check_missing_dependencies() for pkg in missing_dependency_list: retcode = waagent.Run('yum -y install ' + pkg) if retcode > 0: self.hutil.error("Failed to install missing dependency: " + pkg) def check(self, category): """ Check valid upgrades, Return the package list to download & upgrade """ if category == self.category_all: check_cmd = self.check_cmd elif category == self.category_required: check_cmd = self.check_security_cmd to_download = [] retcode,output = waagent.RunGetOutput(check_cmd, chk_err=False) if retcode == 0: return 0, to_download elif retcode == 100: lines = output.strip().split('\n') for line in lines: line = re.split(r'\s+', line.strip()) if len(line) != 3: break to_download.append(line[0]) return 0, to_download elif retcode == 1: return 1, to_download def download_package(self, package): retcode = waagent.Run(self.download_cmd + ' ' + package, chk_err=False) # Yum exit code is not 0 even if succeed, so check if the package rpm exsits to verify that downloading succeeds. return self.check_download(package) def patch_package(self, package): return waagent.Run(self.patch_cmd + ' ' + package) def check_reboot(self): retcode,last_kernel = waagent.RunGetOutput("rpm -q --last kernel") last_kernel = last_kernel.split()[0][7:] retcode,current_kernel = waagent.RunGetOutput('uname -r') current_kernel = current_kernel.strip() self.reboot_required = (last_kernel != current_kernel) def report(self): """ TODO: Report the detail status of patching """ for package_patched in self.patched: self.info_pkg(package_patched) def info_pkg(self, pkg_name): """ Return details about a package """ retcode,output = waagent.RunGetOutput(self.status_cmd + ' ' + pkg_name) if retcode != 0: self.hutil.error(output) return None installed_pkg_info_list = output.rpartition('Available Packages')[0].strip().split('\n') available_pkg_info_list = output.rpartition('Available Packages')[-1].strip().split('\n') pkg_info = dict() pkg_info['installed'] = dict() pkg_info['available'] = dict() for item in installed_pkg_info_list: if item.startswith('Name'): pkg_info['installed']['name'] = item.split(':')[-1].strip() elif item.startswith('Arch'): pkg_info['installed']['arch'] = item.split(':')[-1].strip() elif item.startswith('Version'): pkg_info['installed']['version'] = item.split(':')[-1].strip() elif item.startswith('Release'): pkg_info['installed']['release'] = item.split(':')[-1].strip() for item in available_pkg_info_list: if item.startswith('Name'): pkg_info['available']['name'] = item.split(':')[-1].strip() elif item.startswith('Arch'): pkg_info['available']['arch'] = item.split(':')[-1].strip() elif item.startswith('Version'): pkg_info['available']['version'] = item.split(':')[-1].strip() elif item.startswith('Release'): pkg_info['available']['release'] = item.split(':')[-1].strip() return pkg_info def check_download(self, pkg_name): pkg_info = self.info_pkg(pkg_name) name = pkg_info['available']['name'] arch = pkg_info['available']['arch'] version = pkg_info['available']['version'] release = pkg_info['available']['release'] package = '.'.join(['-'.join([name, version, release]), arch, 'rpm']) retcode,output = waagent.RunGetOutput('cd ' + self.cache_dir + ';find . -name "'+ package + '"') if retcode != 0: self.hutil.error("Unable to check whether the downloading secceeds") else: if output == '': return 1 else: return 0 def check_missing_dependencies(self): retcode, output = waagent.RunGetOutput('package-cleanup --problems', chk_err=False) missing_dependency_list = [] for line in output.split('\n'): if 'requires' not in line: continue words = line.split() missing_dependency = words[words.index('requires') + 1] if missing_dependency not in missing_dependency_list: missing_dependency_list.append(missing_dependency) return missing_dependency_list