win_installer.py 2.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. # -*- coding: utf-8 -*-
  2. '''
  3. :copyright: Copyright 2013-2017 by the SaltStack Team, see AUTHORS for more details.
  4. :license: Apache 2.0, see LICENSE for more details.
  5. tests.support.win_installer
  6. ~~~~~~~~~~~~~~~~~~~~~~~~~~~
  7. Fetches the binary Windows installer
  8. '''
  9. from __future__ import absolute_import
  10. import hashlib
  11. import requests
  12. import re
  13. PREFIX = 'Salt-Minion-'
  14. REPO = "https://repo.saltstack.com/windows"
  15. def iter_installers(content):
  16. '''
  17. Parse a list of windows installer links and their corresponding md5
  18. checksum links.
  19. '''
  20. HREF_RE = "<a href=\"(.*?)\">"
  21. installer, md5 = None, None
  22. for m in re.finditer(HREF_RE, content):
  23. x = m.groups()[0]
  24. if not x.startswith(PREFIX):
  25. continue
  26. if x.endswith(('zip', 'sha256')):
  27. continue
  28. if installer:
  29. if x != installer + '.md5':
  30. raise Exception("Unable to parse response")
  31. md5 = x
  32. yield installer, md5
  33. installer, md5 = None, None
  34. else:
  35. installer = x
  36. def split_installer(name):
  37. '''
  38. Return a tuple of the salt version, python verison and architecture from an
  39. installer name.
  40. '''
  41. x = name[len(PREFIX):]
  42. return x.split('-')[:3]
  43. def latest_version(repo=REPO):
  44. '''
  45. Return the latest version found on the salt repository webpage.
  46. '''
  47. content = requests.get(repo).content.decode('utf-8')
  48. for name, md5 in iter_installers(content):
  49. pass
  50. return split_installer(name)[0]
  51. def installer_name(salt_ver, py_ver='Py2', arch='AMD64'):
  52. '''
  53. Create an installer file name
  54. '''
  55. return "Salt-Minion-{}-{}-{}-Setup.exe".format(salt_ver, py_ver, arch)
  56. def latest_installer_name(repo=REPO, **kwargs):
  57. '''
  58. Fetch the latest installer name
  59. '''
  60. return installer_name(latest_version(repo), **kwargs)
  61. def download_and_verify(fp, name, repo=REPO):
  62. '''
  63. Download an installer and verify it's contents.
  64. '''
  65. md5 = "{}.md5".format(name)
  66. url = lambda x: "{}/{}".format(repo, x)
  67. resp = requests.get(url(md5))
  68. if resp.status_code != 200:
  69. raise Exception("Unable to fetch installer md5")
  70. installer_md5 = resp.text.strip().split()[0].lower()
  71. resp = requests.get(url(name), stream=True)
  72. if resp.status_code != 200:
  73. raise Exception("Unable to fetch installer")
  74. md5hsh = hashlib.md5()
  75. for chunk in resp.iter_content(chunk_size=1024):
  76. md5hsh.update(chunk)
  77. fp.write(chunk)
  78. if md5hsh.hexdigest() != installer_md5:
  79. raise Exception("Installer's hash does not match {} != {}".format(
  80. md5hsh.hexdigest(), installer_md5
  81. ))