install_packages.py 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. #!/usr/bin/env python
  2. """
  3. Licensed to the Apache Software Foundation (ASF) under one
  4. or more contributor license agreements. See the NOTICE file
  5. distributed with this work for additional information
  6. regarding copyright ownership. The ASF licenses this file
  7. to you under the Apache License, Version 2.0 (the
  8. "License"); you may not use this file except in compliance
  9. with the License. You may obtain a copy of the License at
  10. http://www.apache.org/licenses/LICENSE-2.0
  11. Unless required by applicable law or agreed to in writing, software
  12. distributed under the License is distributed on an "AS IS" BASIS,
  13. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. See the License for the specific language governing permissions and
  15. limitations under the License.
  16. Ambari Agent
  17. """
  18. import json
  19. import sys
  20. import re
  21. import traceback
  22. from resource_management import *
  23. from resource_management.libraries.functions.list_ambari_managed_repos import list_ambari_managed_repos
  24. from ambari_commons.os_check import OSCheck, OSConst
  25. from resource_management.libraries.functions.packages_analyzer import allInstalledPackages
  26. from resource_management.core.shell import call
  27. from resource_management.libraries.functions.default import default
  28. class InstallPackages(Script):
  29. """
  30. This script is a part of Rolling Upgrade workflow and is described at
  31. appropriate design doc.
  32. It installs repositories to the node and then installs packages.
  33. For now, repositories are installed into individual files.
  34. """
  35. UBUNTU_REPO_COMPONENTS_POSTFIX = ["main"]
  36. REPO_FILE_NAME_PREFIX = 'HDP-'
  37. def actionexecute(self, env):
  38. delayed_fail = False
  39. package_install_result = False
  40. # Parse parameters
  41. config = Script.get_config()
  42. # Select dict that contains parameters
  43. try:
  44. repository_version = config['roleParams']['repository_version']
  45. base_urls = json.loads(config['roleParams']['base_urls'])
  46. package_list = json.loads(config['roleParams']['package_list'])
  47. stack_id = config['roleParams']['stack_id']
  48. except KeyError:
  49. # Last try
  50. repository_version = config['commandParams']['repository_version']
  51. base_urls = json.loads(config['commandParams']['base_urls'])
  52. package_list = json.loads(config['commandParams']['package_list'])
  53. stack_id = config['commandParams']['stack_id']
  54. # Install/update repositories
  55. installed_repositories = []
  56. current_repositories = ['base'] # Some our packages are installed from the base repo
  57. current_repo_files = set(['base'])
  58. old_versions = self.hdp_versions()
  59. try:
  60. append_to_file = False
  61. for url_info in base_urls:
  62. repo_name, repo_file = self.install_repository(url_info, repository_version, append_to_file)
  63. current_repositories.append(repo_name)
  64. current_repo_files.add(repo_file)
  65. append_to_file = True
  66. installed_repositories = list_ambari_managed_repos()
  67. except Exception, err:
  68. print "Can not distribute repositories."
  69. print traceback.format_exc()
  70. delayed_fail = True
  71. # Install packages
  72. if not delayed_fail:
  73. packages_were_checked = False
  74. try:
  75. packages_installed_before = []
  76. allInstalledPackages(packages_installed_before)
  77. packages_installed_before = [package[0] for package in packages_installed_before]
  78. packages_were_checked = True
  79. filtered_package_list = self.filter_package_list(package_list)
  80. for package in filtered_package_list:
  81. name = self.format_package_name(package['name'], repository_version)
  82. Package(name, use_repos=list(current_repo_files) if OSCheck.is_ubuntu_family() else current_repositories)
  83. package_install_result = True
  84. except Exception, err:
  85. print "Can not install packages."
  86. print traceback.format_exc()
  87. delayed_fail = True
  88. # Remove already installed packages in case of fail
  89. if packages_were_checked and packages_installed_before:
  90. packages_installed_after = []
  91. allInstalledPackages(packages_installed_after)
  92. packages_installed_after = [package[0] for package in packages_installed_after]
  93. packages_installed_before = set(packages_installed_before)
  94. new_packages_installed = [package for package in packages_installed_after if package not in packages_installed_before]
  95. if OSCheck.is_ubuntu_family():
  96. package_version_string = repository_version.replace('.', '-')
  97. else:
  98. package_version_string = repository_version.replace('-', '_')
  99. package_version_string = package_version_string.replace('.', '_')
  100. for package in new_packages_installed:
  101. if package_version_string and (package_version_string in package):
  102. Package(package, action="remove")
  103. # Build structured output
  104. structured_output = {
  105. 'ambari_repositories': installed_repositories,
  106. 'installed_repository_version': repository_version,
  107. 'stack_id': stack_id,
  108. 'package_installation_result': 'SUCCESS' if package_install_result else 'FAIL'
  109. }
  110. if package_install_result:
  111. new_versions = self.hdp_versions()
  112. deltas = set(new_versions) - set(old_versions)
  113. if 1 == len(deltas):
  114. structured_output['actual_version'] = next(iter(deltas))
  115. self.put_structured_out(structured_output)
  116. # Provide correct exit code
  117. if delayed_fail:
  118. raise Fail("Failed to distribute repositories/install packages")
  119. def install_repository(self, url_info, repository_version, append_to_file):
  120. template = "repo_suse_rhel.j2" if OSCheck.is_redhat_family() or OSCheck.is_suse_family() else "repo_ubuntu.j2"
  121. repo = {
  122. 'repoName': "{0}-{1}".format(url_info['name'], repository_version)
  123. }
  124. if not 'baseUrl' in url_info:
  125. repo['baseurl'] = None
  126. else:
  127. repo['baseurl'] = url_info['baseUrl']
  128. if not 'mirrorsList' in url_info:
  129. repo['mirrorsList'] = None
  130. else:
  131. repo['mirrorsList'] = url_info['mirrorsList']
  132. ubuntu_components = [url_info['name']] + self.UBUNTU_REPO_COMPONENTS_POSTFIX
  133. file_name = self.REPO_FILE_NAME_PREFIX + repository_version
  134. Repository(repo['repoName'],
  135. action = "create",
  136. base_url = repo['baseurl'],
  137. mirror_list = repo['mirrorsList'],
  138. repo_file_name = file_name,
  139. repo_template = template,
  140. append_to_file = append_to_file,
  141. components = ubuntu_components, # ubuntu specific
  142. )
  143. return repo['repoName'], file_name
  144. def format_package_name(self, package_name, repo_id):
  145. """
  146. This method overcomes problems at SLES SP3. Zypper here behaves differently
  147. than at SP1, and refuses to install packages by mask if there is any installed package that
  148. matches this mask.
  149. So we preppend concrete HDP version to mask under Suse
  150. """
  151. if OSCheck.is_suse_family() and '*' in package_name:
  152. mask_version = re.search(r'((_\d+)*(_)?\*)', package_name).group(0)
  153. formatted_version = '_' + repo_id.replace('.', '_').replace('-', '_') + '*'
  154. return package_name.replace(mask_version, formatted_version)
  155. else:
  156. return package_name
  157. def hdp_versions(self):
  158. code, out = call("hdp-select versions")
  159. if 0 == code:
  160. versions = []
  161. for line in out.splitlines():
  162. versions.append(line.rstrip('\n'))
  163. return versions
  164. else:
  165. return []
  166. def filter_package_list(self, package_list):
  167. """
  168. Here we filter packages that are managed with custom logic in package
  169. scripts. Usually this packages come from system repositories, and either
  170. are not available when we restrict repository list, or should not be
  171. installed on host at all.
  172. :param package_list: original list
  173. :return: filtered package_list
  174. """
  175. filtered_package_list = []
  176. # hadoop-lzo package is installed only if LZO compression is enabled
  177. lzo_packages = ['hadoop-lzo', 'lzo', 'hadoop-lzo-native', 'liblzo2-2', 'hadooplzo']
  178. has_lzo = False
  179. io_compression_codecs = default("/configurations/core-site/io.compression.codecs", None)
  180. if io_compression_codecs:
  181. has_lzo = "com.hadoop.compression.lzo" in io_compression_codecs.lower()
  182. for package in package_list:
  183. skip_package = False
  184. # mysql* package logic is managed at HIVE scripts
  185. if package['name'].startswith('mysql'):
  186. skip_package = True
  187. # Ambari metrics packages should not be upgraded during RU
  188. if package['name'].startswith('ambari-metrics'):
  189. skip_package = True
  190. if not has_lzo:
  191. for lzo_package in lzo_packages:
  192. if package['name'].startswith(lzo_package):
  193. skip_package = True
  194. break
  195. if not skip_package:
  196. filtered_package_list.append(package)
  197. return filtered_package_list
  198. if __name__ == "__main__":
  199. InstallPackages().execute()