smoke_test_xpack_rc.py 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. # Smoke-tests a x-pack release candidate
  2. #
  3. # 1. Downloads the zip file from the staging URL
  4. # 3. Installs x-pack plugin
  5. # 4. Starts one node for zip package and checks:
  6. # -- if x-pack plugin is loaded
  7. # -- checks xpack info page, if response returns correct version and feature set info
  8. #
  9. # USAGE:
  10. #
  11. # python3 -B ./dev-tools/smoke_test_rc.py --version 5.0.0-beta1 --hash bfa3e47
  12. #
  13. import argparse
  14. import tempfile
  15. import os
  16. import signal
  17. import shutil
  18. import urllib
  19. import urllib.request
  20. import time
  21. import json
  22. import base64
  23. from http.client import HTTPConnection
  24. # in case of debug, uncomment
  25. # HTTPConnection.debuglevel = 4
  26. try:
  27. JAVA_HOME = os.environ['JAVA_HOME']
  28. except KeyError:
  29. raise RuntimeError("""
  30. Please set JAVA_HOME in the env before running release tool
  31. On OSX use: export JAVA_HOME=`/usr/libexec/java_home -v '1.8*'`""")
  32. def java_exe():
  33. path = JAVA_HOME
  34. return 'export JAVA_HOME="%s" PATH="%s/bin:$PATH" JAVACMD="%s/bin/java"' % (path, path, path)
  35. def verify_java_version(version):
  36. s = os.popen('%s; java -version 2>&1' % java_exe()).read()
  37. if ' version "%s.' % version not in s:
  38. raise RuntimeError('got wrong version for java %s:\n%s' % (version, s))
  39. def read_fully(file):
  40. with open(file, encoding='utf-8') as f:
  41. return f.read()
  42. def wait_for_node_startup(es_dir, timeout=60, headers={}):
  43. print(' Waiting until node becomes available for at most %s seconds' % timeout)
  44. for _ in range(timeout):
  45. conn = None
  46. try:
  47. time.sleep(1)
  48. host = get_host_from_ports_file(es_dir)
  49. conn = HTTPConnection(host, timeout=1)
  50. conn.request('GET', '/', headers=headers)
  51. res = conn.getresponse()
  52. if res.status == 200:
  53. return True
  54. except IOError as e:
  55. pass
  56. #that is ok it might not be there yet
  57. finally:
  58. if conn:
  59. conn.close()
  60. return False
  61. def download_release(version, release_hash, url):
  62. print('Downloading release %s from %s' % (version, url))
  63. tmp_dir = tempfile.mkdtemp()
  64. try:
  65. downloaded_files = []
  66. print(' ' + '*' * 80)
  67. print(' Downloading %s' % (url))
  68. file = ('elasticsearch-%s.zip' % version)
  69. artifact_path = os.path.join(tmp_dir, file)
  70. downloaded_files.append(artifact_path)
  71. urllib.request.urlretrieve(url, os.path.join(tmp_dir, file))
  72. print(' ' + '*' * 80)
  73. print()
  74. smoke_test_release(version, downloaded_files, release_hash)
  75. print(' SUCCESS')
  76. finally:
  77. shutil.rmtree(tmp_dir)
  78. def get_host_from_ports_file(es_dir):
  79. return read_fully(os.path.join(es_dir, 'logs/http.ports')).splitlines()[0]
  80. def smoke_test_release(release, files, release_hash):
  81. for release_file in files:
  82. if not os.path.isfile(release_file):
  83. raise RuntimeError('Smoketest failed missing file %s' % (release_file))
  84. tmp_dir = tempfile.mkdtemp()
  85. run('unzip %s -d %s' % (release_file, tmp_dir))
  86. es_dir = os.path.join(tmp_dir, 'elasticsearch-%s' % (release))
  87. es_run_path = os.path.join(es_dir, 'bin/elasticsearch')
  88. print(' Smoke testing package [%s]' % release_file)
  89. es_plugin_path = os.path.join(es_dir, 'bin/elasticsearch-plugin')
  90. print(' Install xpack [%s]')
  91. run('%s; ES_JAVA_OPTS="-Des.plugins.staging=%s" %s install -b x-pack' % (java_exe(), release_hash, es_plugin_path))
  92. headers = { 'Authorization' : 'Basic %s' % base64.b64encode(b"es_admin:foobar").decode("UTF-8") }
  93. es_shield_path = os.path.join(es_dir, 'bin/x-pack/users')
  94. print(" Install dummy shield user")
  95. run('%s; %s useradd es_admin -r superuser -p foobar' % (java_exe(), es_shield_path))
  96. print(' Starting elasticsearch daemon from [%s]' % es_dir)
  97. try:
  98. run('%s; %s -Enode.name=smoke_tester -Ecluster.name=prepare_release -Erepositories.url.allowed_urls=http://snapshot.test* %s -Epidfile=%s -Enode.portsfile=true'
  99. % (java_exe(), es_run_path, '-d', os.path.join(es_dir, 'es-smoke.pid')))
  100. if not wait_for_node_startup(es_dir, headers=headers):
  101. print("elasticsearch logs:")
  102. print('*' * 80)
  103. logs = read_fully(os.path.join(es_dir, 'logs/prepare_release.log'))
  104. print(logs)
  105. print('*' * 80)
  106. raise RuntimeError('server didn\'t start up')
  107. try: # we now get / and /_nodes to fetch basic infos like hashes etc and the installed plugins
  108. host = get_host_from_ports_file(es_dir)
  109. conn = HTTPConnection(host, timeout=20)
  110. # check if plugin is loaded
  111. conn.request('GET', '/_nodes/plugins?pretty=true', headers=headers)
  112. res = conn.getresponse()
  113. if res.status == 200:
  114. nodes = json.loads(res.read().decode("utf-8"))['nodes']
  115. for _, node in nodes.items():
  116. node_plugins = node['plugins']
  117. for node_plugin in node_plugins:
  118. if node_plugin['name'] != 'x-pack':
  119. raise RuntimeError('Unexpected plugin %s, expected x-pack only' % node_plugin['name'])
  120. else:
  121. raise RuntimeError('Expected HTTP 200 but got %s' % res.status)
  122. # check if license is the default one
  123. # also sleep for few more seconds, as the initial license generation might take some time
  124. time.sleep(5)
  125. conn.request('GET', '/_xpack', headers=headers)
  126. res = conn.getresponse()
  127. if res.status == 200:
  128. xpack = json.loads(res.read().decode("utf-8"))
  129. if xpack['license']['type'] != 'trial':
  130. raise RuntimeError('expected license type to be trial, was %s' % xpack['license']['type'])
  131. if xpack['license']['mode'] != 'trial':
  132. raise RuntimeError('expected license mode to be trial, was %s' % xpack['license']['mode'])
  133. if xpack['license']['status'] != 'active':
  134. raise RuntimeError('expected license status to be active, was %s' % xpack['license']['active'])
  135. else:
  136. raise RuntimeError('Expected HTTP 200 but got %s' % res.status)
  137. finally:
  138. conn.close()
  139. finally:
  140. pid_path = os.path.join(es_dir, 'es-smoke.pid')
  141. if os.path.exists(pid_path): # try reading the pid and kill the node
  142. pid = int(read_fully(pid_path))
  143. os.kill(pid, signal.SIGKILL)
  144. shutil.rmtree(tmp_dir)
  145. print(' ' + '*' * 80)
  146. print()
  147. # console colors
  148. COLOR_OK = '\033[92m'
  149. COLOR_END = '\033[0m'
  150. def run(command, env_vars=None):
  151. if env_vars:
  152. for key, value in env_vars.items():
  153. os.putenv(key, value)
  154. print('*** Running: %s%s%s' % (COLOR_OK, command, COLOR_END))
  155. if os.system(command):
  156. raise RuntimeError(' FAILED: %s' % (command))
  157. if __name__ == "__main__":
  158. parser = argparse.ArgumentParser(description='SmokeTests a Release Candidate from S3 staging repo')
  159. parser.add_argument('--version', '-v', dest='version', default=None,
  160. help='The Elasticsearch Version to smoke-tests', required=True)
  161. parser.add_argument('--hash', '-r', dest='hash', default=None, required=True,
  162. help='The sha1 short hash of the release git commit to smoketest')
  163. parser.add_argument('--fetch_url', '-u', dest='url', default=None,
  164. help='Fetched from the specified URL')
  165. parser.set_defaults(hash=None)
  166. parser.set_defaults(version=None)
  167. parser.set_defaults(url=None)
  168. args = parser.parse_args()
  169. version = args.version
  170. hash = args.hash
  171. url = args.url
  172. verify_java_version('1.8')
  173. if url:
  174. download_url = url
  175. else:
  176. download_url = 'https://staging.elastic.co/%s-%s/downloads/elasticsearch/elasticsearch-%s.zip' % (version, hash, version)
  177. download_release(version, hash, download_url)