CI for the TripleO project
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

emit_releases_file.py 7.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. import argparse
  2. import logging
  3. import logging.handlers
  4. import os
  5. import re
  6. import requests
  7. import yaml
  8. # Define releases
  9. RELEASES = ['newton', 'ocata', 'pike', 'queens', 'master']
  10. # Define long term releases
  11. LONG_TERM_SUPPORT_RELEASES = ['queens']
  12. def get_relative_release(release, relative_idx):
  13. current_idx = RELEASES.index(release)
  14. absolute_idx = current_idx + relative_idx
  15. return RELEASES[absolute_idx]
  16. def setup_logging(log_file):
  17. '''Setup logging for the script'''
  18. logger = logging.getLogger('emit-releases')
  19. logger.setLevel(logging.DEBUG)
  20. log_handler = logging.handlers.WatchedFileHandler(
  21. os.path.expanduser(log_file))
  22. logger.addHandler(log_handler)
  23. def load_featureset_file(featureset_file):
  24. logger = logging.getLogger('emit-releases')
  25. try:
  26. with open(featureset_file, 'r') as stream:
  27. featureset = yaml.safe_load(stream)
  28. except Exception as e:
  29. logger.error("The featureset file: {} can not be "
  30. "opened.".format(featureset_file))
  31. logger.exception(e)
  32. raise e
  33. return featureset
  34. def get_dlrn_hash(release, hash_name, retries=10):
  35. logger = logging.getLogger('emit-releases')
  36. full_hash_pattern = re.compile('[a-z,0-9]{40}_[a-z,0-9]{8}')
  37. repo_url = ('https://trunk.rdoproject.org/centos7-%s/%s/delorean.repo'
  38. % (release, hash_name))
  39. for retry_num in range(retries):
  40. repo_file = None
  41. # Timeout if initial connection is longer than default
  42. # TCP packet retransmission window (3 secs), or if the
  43. # sending of the data takes more than 27 seconds.
  44. try:
  45. repo_file = requests.get(repo_url, timeout=(3.05, 27))
  46. except Exception as e:
  47. logger.exception(e)
  48. pass
  49. else:
  50. if repo_file is not None and repo_file.ok:
  51. break
  52. if repo_file is None or not repo_file.ok:
  53. raise RuntimeError("Failed to retrieve repo file from {} after "
  54. "{} retries".format(repo_url, retries))
  55. full_hash = full_hash_pattern.findall(repo_file.content)
  56. return full_hash[0]
  57. def compose_releases_dictionary(stable_release, featureset):
  58. logger = logging.getLogger('emit-releases')
  59. if stable_release not in RELEASES:
  60. raise RuntimeError("The {} release is not supported by this tool"
  61. "Supported releases: {}".format(
  62. stable_release, RELEASES))
  63. if (featureset.get('overcloud_upgrade') or
  64. featureset.get('undercloud_upgrade')) and \
  65. stable_release == RELEASES[0]:
  66. raise RuntimeError("Cannot upgrade to {}".format(RELEASES[0]))
  67. if featureset.get('overcloud_upgrade') and \
  68. featureset.get('undercloud_upgrade'):
  69. raise RuntimeError("This tool currently only supports upgrading the "
  70. "undercloud OR the overcloud NOT both.")
  71. if (featureset.get('overcloud_upgrade') or
  72. featureset.get('ffu_overcloud_upgrade')) and \
  73. not featureset.get('mixed_upgrade'):
  74. raise RuntimeError("Overcloud upgrade has to be mixed upgrades")
  75. if featureset.get('ffu_overcloud_upgrade') and \
  76. stable_release not in LONG_TERM_SUPPORT_RELEASES:
  77. raise RuntimeError(
  78. "{} is not a long-term support release, and cannot be "
  79. "used in a fast forward upgrade. Current long-term support "
  80. "releases: {}".format(stable_release, LONG_TERM_SUPPORT_RELEASES))
  81. releases_dictionary = {
  82. 'undercloud_install_release': stable_release,
  83. 'undercloud_install_hash': 'current-tripleo',
  84. 'undercloud_target_release': stable_release,
  85. 'undercloud_target_hash': 'current-tripleo',
  86. 'overcloud_deploy_release': stable_release,
  87. 'overcloud_deploy_hash': 'current-tripleo',
  88. 'overcloud_target_release': stable_release,
  89. 'overcloud_target_hash': 'current-tripleo'
  90. }
  91. if featureset.get('mixed_upgrade'):
  92. if featureset.get('overcloud_upgrade'):
  93. logger.info('Doing an overcloud upgrade')
  94. deploy_release = get_relative_release(stable_release, -1)
  95. releases_dictionary['overcloud_deploy_release'] = deploy_release
  96. elif featureset.get('ffu_overcloud_upgrade'):
  97. logger.info('Doing an overcloud fast forward upgrade')
  98. deploy_release = get_relative_release(stable_release, -3)
  99. releases_dictionary['overcloud_deploy_release'] = deploy_release
  100. elif featureset.get('undercloud_upgrade'):
  101. logger.info('Doing an undercloud upgrade')
  102. install_release = get_relative_release(stable_release, -1)
  103. releases_dictionary['undercloud_install_release'] = install_release
  104. elif featureset.get('overcloud_update'):
  105. logger.info('Doing an overcloud update')
  106. releases_dictionary['overcloud_deploy_hash'] = \
  107. 'previous-current-tripleo'
  108. logger.debug("stable_release: %s, featureset: %s", stable_release,
  109. featureset)
  110. logger.info('output releases: %s', releases_dictionary)
  111. return releases_dictionary
  112. def shim_convert_old_release_names(releases_names):
  113. # TODO(trown): Remove this shim when we no longer need to use the
  114. # old style double release files.
  115. oc_deploy_release = releases_names['overcloud_deploy_release']
  116. oc_target_release = releases_names['overcloud_target_release']
  117. uc_install_release = releases_names['undercloud_install_release']
  118. if oc_deploy_release != oc_target_release:
  119. release_file = "undercloud-{}-overcloud-{}".format(
  120. uc_install_release, oc_deploy_release)
  121. releases_names['undercloud_install_release'] = release_file
  122. releases_names['undercloud_target_release'] = release_file
  123. releases_names['overcloud_deploy_release'] = release_file
  124. releases_names['overcloud_target_release'] = release_file
  125. return releases_names
  126. if __name__ == '__main__':
  127. default_log_file = '{}.log'.format(os.path.basename(__file__))
  128. default_output_file = '{}.out'.format(os.path.basename(__file__))
  129. parser = argparse.ArgumentParser(
  130. formatter_class=argparse.RawTextHelpFormatter,
  131. description='Get a dictionary of releases from a release '
  132. 'and a featureset file.')
  133. parser.add_argument('--stable-release',
  134. choices=RELEASES,
  135. required=True,
  136. help='Release that the change being tested is from.\n'
  137. 'All other releases are calculated from this\n'
  138. 'basis.')
  139. parser.add_argument('--featureset-file',
  140. required=True,
  141. help='Featureset file which will be introspected to\n'
  142. 'infer what type of upgrade is being performed\n'
  143. '(if any).')
  144. parser.add_argument('--output-file', default=default_output_file,
  145. help='Output file containing dictionary of releases\n'
  146. 'for the provided featureset and release.\n'
  147. '(default: %(default)s)')
  148. parser.add_argument('--log-file', default=default_log_file,
  149. help='log file to print debug information from\n'
  150. 'running the script.\n'
  151. '(default: %(default)s)')
  152. args = parser.parse_args()
  153. setup_logging(args.log_file)
  154. logger = logging.getLogger('emit-releases')
  155. featureset = load_featureset_file(args.featureset_file)
  156. releases_dictionary = compose_releases_dictionary(args.stable_release,
  157. featureset)
  158. releases_dictionary = shim_convert_old_release_names(
  159. releases_dictionary)