mirror of
https://github.com/valitydev/salt.git
synced 2024-11-07 08:58:59 +00:00
Merge pull request #46769 from dwoz/wincloudtest
Adding windows minion tests for salt cloud
This commit is contained in:
commit
3bac9717f4
@ -2336,6 +2336,9 @@ def wait_for_instance(
|
|||||||
use_winrm = config.get_cloud_config_value(
|
use_winrm = config.get_cloud_config_value(
|
||||||
'use_winrm', vm_, __opts__, default=False
|
'use_winrm', vm_, __opts__, default=False
|
||||||
)
|
)
|
||||||
|
winrm_verify_ssl = config.get_cloud_config_value(
|
||||||
|
'winrm_verify_ssl', vm_, __opts__, default=True
|
||||||
|
)
|
||||||
|
|
||||||
if win_passwd and win_passwd == 'auto':
|
if win_passwd and win_passwd == 'auto':
|
||||||
log.debug('Waiting for auto-generated Windows EC2 password')
|
log.debug('Waiting for auto-generated Windows EC2 password')
|
||||||
@ -2407,7 +2410,8 @@ def wait_for_instance(
|
|||||||
winrm_port,
|
winrm_port,
|
||||||
username,
|
username,
|
||||||
win_passwd,
|
win_passwd,
|
||||||
timeout=ssh_connect_timeout):
|
timeout=ssh_connect_timeout,
|
||||||
|
verify=winrm_verify_ssl):
|
||||||
raise SaltCloudSystemExit(
|
raise SaltCloudSystemExit(
|
||||||
'Failed to authenticate against remote windows host'
|
'Failed to authenticate against remote windows host'
|
||||||
)
|
)
|
||||||
|
@ -515,7 +515,10 @@ def bootstrap(vm_, opts=None):
|
|||||||
'winrm_port', vm_, opts, default=5986
|
'winrm_port', vm_, opts, default=5986
|
||||||
)
|
)
|
||||||
deploy_kwargs['winrm_use_ssl'] = salt.config.get_cloud_config_value(
|
deploy_kwargs['winrm_use_ssl'] = salt.config.get_cloud_config_value(
|
||||||
'winrm_use_ssl', vm_, opts, default=True
|
'winrm_use_ssl', vm_, opts, default=True
|
||||||
|
)
|
||||||
|
deploy_kwargs['winrm_verify_ssl'] = salt.config.get_cloud_config_value(
|
||||||
|
'winrm_verify_ssl', vm_, opts, default=True
|
||||||
)
|
)
|
||||||
if saltify_driver:
|
if saltify_driver:
|
||||||
deploy_kwargs['port_timeout'] = 1 # No need to wait/retry with Saltify
|
deploy_kwargs['port_timeout'] = 1 # No need to wait/retry with Saltify
|
||||||
@ -843,7 +846,7 @@ def wait_for_winexesvc(host, port, username, password, timeout=900):
|
|||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
|
|
||||||
|
|
||||||
def wait_for_winrm(host, port, username, password, timeout=900, use_ssl=True):
|
def wait_for_winrm(host, port, username, password, timeout=900, use_ssl=True, verify=True):
|
||||||
'''
|
'''
|
||||||
Wait until WinRM connection can be established.
|
Wait until WinRM connection can be established.
|
||||||
'''
|
'''
|
||||||
@ -853,14 +856,20 @@ def wait_for_winrm(host, port, username, password, timeout=900, use_ssl=True):
|
|||||||
host, port
|
host, port
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
transport = 'ssl'
|
||||||
|
if not use_ssl:
|
||||||
|
transport = 'plaintext'
|
||||||
trycount = 0
|
trycount = 0
|
||||||
while True:
|
while True:
|
||||||
trycount += 1
|
trycount += 1
|
||||||
try:
|
try:
|
||||||
transport = 'ssl'
|
winrm_kwargs = {'target': host,
|
||||||
if not use_ssl:
|
'auth': (username, password),
|
||||||
transport = 'plaintext'
|
'transport': transport}
|
||||||
s = winrm.Session(host, auth=(username, password), transport=transport)
|
if not verify:
|
||||||
|
log.debug("SSL validation for WinRM disabled.")
|
||||||
|
winrm_kwargs['server_cert_validation'] = 'ignore'
|
||||||
|
s = winrm.Session(**winrm_kwargs)
|
||||||
if hasattr(s.protocol, 'set_timeout'):
|
if hasattr(s.protocol, 'set_timeout'):
|
||||||
s.protocol.set_timeout(15)
|
s.protocol.set_timeout(15)
|
||||||
log.trace('WinRM endpoint url: {0}'.format(s.url))
|
log.trace('WinRM endpoint url: {0}'.format(s.url))
|
||||||
@ -1008,6 +1017,7 @@ def deploy_windows(host,
|
|||||||
use_winrm=False,
|
use_winrm=False,
|
||||||
winrm_port=5986,
|
winrm_port=5986,
|
||||||
winrm_use_ssl=True,
|
winrm_use_ssl=True,
|
||||||
|
winrm_verify_ssl=True,
|
||||||
**kwargs):
|
**kwargs):
|
||||||
'''
|
'''
|
||||||
Copy the install files to a remote Windows box, and execute them
|
Copy the install files to a remote Windows box, and execute them
|
||||||
@ -1034,7 +1044,8 @@ def deploy_windows(host,
|
|||||||
if HAS_WINRM and use_winrm:
|
if HAS_WINRM and use_winrm:
|
||||||
winrm_session = wait_for_winrm(host=host, port=winrm_port,
|
winrm_session = wait_for_winrm(host=host, port=winrm_port,
|
||||||
username=username, password=password,
|
username=username, password=password,
|
||||||
timeout=port_timeout * 60, use_ssl=winrm_use_ssl)
|
timeout=port_timeout * 60, use_ssl=winrm_use_ssl,
|
||||||
|
verify=winrm_verify_ssl)
|
||||||
if winrm_session is not None:
|
if winrm_session is not None:
|
||||||
service_available = True
|
service_available = True
|
||||||
else:
|
else:
|
||||||
|
@ -8,14 +8,18 @@ from __future__ import absolute_import
|
|||||||
import os
|
import os
|
||||||
import random
|
import random
|
||||||
import string
|
import string
|
||||||
|
import yaml
|
||||||
|
|
||||||
# Import Salt Libs
|
# Import Salt Libs
|
||||||
from salt.config import cloud_providers_config
|
from salt.config import cloud_providers_config
|
||||||
|
import salt.utils
|
||||||
|
|
||||||
# Import Salt Testing Libs
|
# Import Salt Testing Libs
|
||||||
from tests.support.case import ShellCase
|
from tests.support.case import ShellCase
|
||||||
from tests.support.paths import FILES
|
from tests.support.paths import FILES
|
||||||
from tests.support.helpers import expensiveTest
|
from tests.support.helpers import expensiveTest
|
||||||
|
from tests.support.unit import expectedFailure
|
||||||
|
from tests.support import win_installer
|
||||||
|
|
||||||
# Import Third-Party Libs
|
# Import Third-Party Libs
|
||||||
from salt.ext.six.moves import range # pylint: disable=import-error,redefined-builtin
|
from salt.ext.six.moves import range # pylint: disable=import-error,redefined-builtin
|
||||||
@ -39,6 +43,38 @@ class EC2Test(ShellCase):
|
|||||||
'''
|
'''
|
||||||
Integration tests for the EC2 cloud provider in Salt-Cloud
|
Integration tests for the EC2 cloud provider in Salt-Cloud
|
||||||
'''
|
'''
|
||||||
|
TIMEOUT = 500
|
||||||
|
|
||||||
|
def _installer_name(self):
|
||||||
|
'''
|
||||||
|
Determine the downloaded installer name by searching the files
|
||||||
|
directory for the firt file that loosk like an installer.
|
||||||
|
'''
|
||||||
|
for path, dirs, files in os.walk(FILES):
|
||||||
|
for file in files:
|
||||||
|
if file.startswith(win_installer.PREFIX):
|
||||||
|
return file
|
||||||
|
break
|
||||||
|
return
|
||||||
|
|
||||||
|
def _fetch_latest_installer(self):
|
||||||
|
'''
|
||||||
|
Download the latest Windows installer executable
|
||||||
|
'''
|
||||||
|
name = win_installer.latest_installer_name()
|
||||||
|
path = os.path.join(FILES, name)
|
||||||
|
with salt.utils.fopen(path, 'wb') as fp:
|
||||||
|
win_installer.download_and_verify(fp, name)
|
||||||
|
return name
|
||||||
|
|
||||||
|
def _ensure_installer(self):
|
||||||
|
'''
|
||||||
|
Make sure the testing environment has a Windows installer executbale.
|
||||||
|
'''
|
||||||
|
name = self._installer_name()
|
||||||
|
if name:
|
||||||
|
return name
|
||||||
|
return self._fetch_latest_installer()
|
||||||
|
|
||||||
@expensiveTest
|
@expensiveTest
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
@ -90,24 +126,51 @@ class EC2Test(ShellCase):
|
|||||||
'missing. Check tests/integration/files/conf/cloud.providers.d/{0}.conf'
|
'missing. Check tests/integration/files/conf/cloud.providers.d/{0}.conf'
|
||||||
.format(PROVIDER_NAME)
|
.format(PROVIDER_NAME)
|
||||||
)
|
)
|
||||||
|
self.INSTALLER = self._ensure_installer()
|
||||||
|
|
||||||
def test_instance(self):
|
def override_profile_config(self, name, data):
|
||||||
|
conf_path = os.path.join(self.get_config_dir(), 'cloud.profiles.d', 'ec2.conf')
|
||||||
|
with salt.utils.fopen(conf_path, 'r') as fp:
|
||||||
|
conf = yaml.safe_load(fp)
|
||||||
|
conf[name].update(data)
|
||||||
|
with salt.utils.fopen(conf_path, 'w') as fp:
|
||||||
|
yaml.dump(conf, fp)
|
||||||
|
|
||||||
|
def copy_file(self, name):
|
||||||
|
'''
|
||||||
|
Copy a file from tests/integration/files to a test's temporary
|
||||||
|
configuration directory. The path to the file which is created will be
|
||||||
|
returned.
|
||||||
|
'''
|
||||||
|
src = os.path.join(FILES, name)
|
||||||
|
dst = os.path.join(self.get_config_dir(), name)
|
||||||
|
with salt.utils.fopen(src, 'rb') as sfp:
|
||||||
|
with salt.utils.fopen(dst, 'wb') as dfp:
|
||||||
|
dfp.write(sfp.read())
|
||||||
|
return dst
|
||||||
|
|
||||||
|
def _test_instance(self, profile='ec2-test', debug=False, timeout=TIMEOUT):
|
||||||
'''
|
'''
|
||||||
Tests creating and deleting an instance on EC2 (classic)
|
Tests creating and deleting an instance on EC2 (classic)
|
||||||
'''
|
'''
|
||||||
|
|
||||||
# create the instance
|
# create the instance
|
||||||
instance = self.run_cloud('-p ec2-test {0}'.format(INSTANCE_NAME), timeout=500)
|
cmd = '-p {0}'.format(profile)
|
||||||
|
if debug:
|
||||||
|
cmd += ' -l debug'
|
||||||
|
cmd += ' {0}'.format(INSTANCE_NAME)
|
||||||
|
instance = self.run_cloud(cmd, timeout=timeout)
|
||||||
ret_str = '{0}:'.format(INSTANCE_NAME)
|
ret_str = '{0}:'.format(INSTANCE_NAME)
|
||||||
|
|
||||||
# check if instance returned with salt installed
|
# check if instance returned with salt installed
|
||||||
try:
|
try:
|
||||||
self.assertIn(ret_str, instance)
|
self.assertIn(ret_str, instance)
|
||||||
except AssertionError:
|
except AssertionError:
|
||||||
self.run_cloud('-d {0} --assume-yes'.format(INSTANCE_NAME), timeout=500)
|
self.run_cloud('-d {0} --assume-yes'.format(INSTANCE_NAME), timeout=timeout)
|
||||||
raise
|
raise
|
||||||
|
|
||||||
# delete the instance
|
# delete the instance
|
||||||
delete = self.run_cloud('-d {0} --assume-yes'.format(INSTANCE_NAME), timeout=500)
|
delete = self.run_cloud('-d {0} --assume-yes'.format(INSTANCE_NAME), timeout=timeout)
|
||||||
ret_str = ' shutting-down'
|
ret_str = ' shutting-down'
|
||||||
|
|
||||||
# check if deletion was performed appropriately
|
# check if deletion was performed appropriately
|
||||||
@ -151,6 +214,80 @@ class EC2Test(ShellCase):
|
|||||||
# check if deletion was performed appropriately
|
# check if deletion was performed appropriately
|
||||||
self.assertIn(ret_str, delete)
|
self.assertIn(ret_str, delete)
|
||||||
|
|
||||||
|
def test_instance(self):
|
||||||
|
'''
|
||||||
|
Tests creating and deleting an instance on EC2 (classic)
|
||||||
|
'''
|
||||||
|
self._test_instance('ec2-test')
|
||||||
|
|
||||||
|
@expectedFailure
|
||||||
|
def test_win2012r2_winexe(self):
|
||||||
|
'''
|
||||||
|
Tests creating and deleting a Windows 2012r2instance on EC2 using
|
||||||
|
winexe (classic)
|
||||||
|
'''
|
||||||
|
# TODO: winexe calls hang and the test fails by timing out. The same
|
||||||
|
# same calls succeed when run outside of the test environment.
|
||||||
|
self.override_profile_config(
|
||||||
|
'ec2-win2012-test',
|
||||||
|
{
|
||||||
|
'use_winrm': False,
|
||||||
|
'user_data': self.copy_file('windows-firewall-winexe.ps1'),
|
||||||
|
'win_installer': self.copy_file(self.INSTALLER),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
self._test_instance('ec2-win2012r2-test', debug=True, timeout=500)
|
||||||
|
|
||||||
|
def test_win2012r2_winrm(self):
|
||||||
|
'''
|
||||||
|
Tests creating and deleting a Windows 2012r2 instance on EC2 using
|
||||||
|
winrm (classic)
|
||||||
|
'''
|
||||||
|
self.override_profile_config(
|
||||||
|
'ec2-win2016-test',
|
||||||
|
{
|
||||||
|
'user_data': self.copy_file('windows-firewall.ps1'),
|
||||||
|
'win_installer': self.copy_file(self.INSTALLER),
|
||||||
|
'winrm_ssl_verify': False,
|
||||||
|
}
|
||||||
|
|
||||||
|
)
|
||||||
|
self._test_instance('ec2-win2012r2-test', debug=True, timeout=500)
|
||||||
|
|
||||||
|
@expectedFailure
|
||||||
|
def test_win2016_winexe(self):
|
||||||
|
'''
|
||||||
|
Tests creating and deleting a Windows 2016 instance on EC2 using winrm
|
||||||
|
(classic)
|
||||||
|
'''
|
||||||
|
# TODO: winexe calls hang and the test fails by timing out. The same
|
||||||
|
# same calls succeed when run outside of the test environment.
|
||||||
|
self.override_profile_config(
|
||||||
|
'ec2-win2016-test',
|
||||||
|
{
|
||||||
|
'use_winrm': False,
|
||||||
|
'user_data': self.copy_file('windows-firewall-winexe.ps1'),
|
||||||
|
'win_installer': self.copy_file(self.INSTALLER),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
self._test_instance('ec2-win2016-test', debug=True, timeout=500)
|
||||||
|
|
||||||
|
def test_win2016_winrm(self):
|
||||||
|
'''
|
||||||
|
Tests creating and deleting a Windows 2016 instance on EC2 using winrm
|
||||||
|
(classic)
|
||||||
|
'''
|
||||||
|
self.override_profile_config(
|
||||||
|
'ec2-win2016-test',
|
||||||
|
{
|
||||||
|
'user_data': self.copy_file('windows-firewall.ps1'),
|
||||||
|
'win_installer': self.copy_file(self.INSTALLER),
|
||||||
|
'winrm_ssl_verify': False,
|
||||||
|
}
|
||||||
|
|
||||||
|
)
|
||||||
|
self._test_instance('ec2-win2016-test', debug=True, timeout=500)
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
'''
|
'''
|
||||||
Clean up after tests
|
Clean up after tests
|
||||||
@ -160,4 +297,4 @@ class EC2Test(ShellCase):
|
|||||||
|
|
||||||
# if test instance is still present, delete it
|
# if test instance is still present, delete it
|
||||||
if ret_str in query:
|
if ret_str in query:
|
||||||
self.run_cloud('-d {0} --assume-yes'.format(INSTANCE_NAME), timeout=500)
|
self.run_cloud('-d {0} --assume-yes'.format(INSTANCE_NAME), timeout=self.TIMEOUT)
|
||||||
|
@ -4,3 +4,31 @@ ec2-test:
|
|||||||
size: t1.micro
|
size: t1.micro
|
||||||
sh_username: ec2-user
|
sh_username: ec2-user
|
||||||
script_args: '-P -Z'
|
script_args: '-P -Z'
|
||||||
|
ec2-win2012r2-test:
|
||||||
|
provider: ec2-config
|
||||||
|
size: t2.micro
|
||||||
|
image: ami-eb1ecd96
|
||||||
|
smb_port: 445
|
||||||
|
win_installer: ''
|
||||||
|
win_username: Administrator
|
||||||
|
win_password: auto
|
||||||
|
userdata_file: ''
|
||||||
|
userdata_template: False
|
||||||
|
use_winrm: True
|
||||||
|
winrm_verify_ssl: False
|
||||||
|
ssh_interface: private_ips
|
||||||
|
deploy: True
|
||||||
|
ec2-win2016-test:
|
||||||
|
provider: ec2-config
|
||||||
|
size: t2.micro
|
||||||
|
image: ami-ed14c790
|
||||||
|
smb_port: 445
|
||||||
|
win_installer: ''
|
||||||
|
win_username: Administrator
|
||||||
|
win_password: auto
|
||||||
|
userdata_file: ''
|
||||||
|
userdata_template: False
|
||||||
|
use_winrm: True
|
||||||
|
winrm_verify_ssl: False
|
||||||
|
ssh_interface: private_ips
|
||||||
|
deploy: True
|
||||||
|
5
tests/integration/files/windows-firewall-winexe.ps1
Normal file
5
tests/integration/files/windows-firewall-winexe.ps1
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<powershell>
|
||||||
|
New-NetFirewallRule -Name "SMB445" -DisplayName "SMB445" -Protocol TCP -LocalPort 445
|
||||||
|
Set-Item (dir wsman:\localhost\Listener\*\Port -Recurse).pspath 445 -Force
|
||||||
|
Restart-Service winrm
|
||||||
|
</powershell>
|
33
tests/integration/files/windows-firewall.ps1
Normal file
33
tests/integration/files/windows-firewall.ps1
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
<powershell>
|
||||||
|
New-NetFirewallRule -Name "SMB445" -DisplayName "SMB445" -Protocol TCP -LocalPort 445
|
||||||
|
New-NetFirewallRule -Name "WINRM5986" -DisplayName "WINRM5986" -Protocol TCP -LocalPort 5986
|
||||||
|
|
||||||
|
winrm quickconfig -q
|
||||||
|
winrm set winrm/config/winrs '@{MaxMemoryPerShellMB="300"}'
|
||||||
|
winrm set winrm/config '@{MaxTimeoutms="1800000"}'
|
||||||
|
winrm set winrm/config/service/auth '@{Basic="true"}'
|
||||||
|
|
||||||
|
$SourceStoreScope = 'LocalMachine'
|
||||||
|
$SourceStorename = 'Remote Desktop'
|
||||||
|
|
||||||
|
$SourceStore = New-Object -TypeName System.Security.Cryptography.X509Certificates.X509Store -ArgumentList $SourceStorename, $SourceStoreScope
|
||||||
|
$SourceStore.Open([System.Security.Cryptography.X509Certificates.OpenFlags]::ReadOnly)
|
||||||
|
|
||||||
|
$cert = $SourceStore.Certificates | Where-Object -FilterScript {
|
||||||
|
$_.subject -like '*'
|
||||||
|
}
|
||||||
|
|
||||||
|
$DestStoreScope = 'LocalMachine'
|
||||||
|
$DestStoreName = 'My'
|
||||||
|
|
||||||
|
$DestStore = New-Object -TypeName System.Security.Cryptography.X509Certificates.X509Store -ArgumentList $DestStoreName, $DestStoreScope
|
||||||
|
$DestStore.Open([System.Security.Cryptography.X509Certificates.OpenFlags]::ReadWrite)
|
||||||
|
$DestStore.Add($cert)
|
||||||
|
|
||||||
|
$SourceStore.Close()
|
||||||
|
$DestStore.Close()
|
||||||
|
|
||||||
|
winrm create winrm/config/listener?Address=*+Transport=HTTPS `@`{Hostname=`"($certId)`"`;CertificateThumbprint=`"($cert.Thumbprint)`"`}
|
||||||
|
|
||||||
|
Restart-Service winrm
|
||||||
|
</powershell>
|
96
tests/support/win_installer.py
Normal file
96
tests/support/win_installer.py
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
'''
|
||||||
|
:copyright: Copyright 2013-2017 by the SaltStack Team, see AUTHORS for more details.
|
||||||
|
:license: Apache 2.0, see LICENSE for more details.
|
||||||
|
|
||||||
|
|
||||||
|
tests.support.win_installer
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Fetches the binary Windows installer
|
||||||
|
'''
|
||||||
|
from __future__ import absolute_import
|
||||||
|
import hashlib
|
||||||
|
import requests
|
||||||
|
import re
|
||||||
|
|
||||||
|
PREFIX = 'Salt-Minion-'
|
||||||
|
REPO = "https://repo.saltstack.com/windows"
|
||||||
|
|
||||||
|
|
||||||
|
def iter_installers(content):
|
||||||
|
'''
|
||||||
|
Parse a list of windows installer links and their corresponding md5
|
||||||
|
checksum links.
|
||||||
|
'''
|
||||||
|
HREF_RE = "<a href=\"(.*?)\">"
|
||||||
|
installer, md5 = None, None
|
||||||
|
for m in re.finditer(HREF_RE, content):
|
||||||
|
x = m.groups()[0]
|
||||||
|
if not x.startswith(PREFIX):
|
||||||
|
continue
|
||||||
|
if x.endswith('zip'):
|
||||||
|
continue
|
||||||
|
if installer:
|
||||||
|
if x != installer + '.md5':
|
||||||
|
raise Exception("Unable to parse response")
|
||||||
|
md5 = x
|
||||||
|
yield installer, md5
|
||||||
|
installer, md5 = None, None
|
||||||
|
else:
|
||||||
|
installer = x
|
||||||
|
|
||||||
|
|
||||||
|
def split_installer(name):
|
||||||
|
'''
|
||||||
|
Return a tuple of the salt version, python verison and architecture from an
|
||||||
|
installer name.
|
||||||
|
'''
|
||||||
|
x = name[len(PREFIX):]
|
||||||
|
return x.split('-')[:3]
|
||||||
|
|
||||||
|
|
||||||
|
def latest_version(repo=REPO):
|
||||||
|
'''
|
||||||
|
Return the latest version found on the salt repository webpage.
|
||||||
|
'''
|
||||||
|
for name, md5 in iter_installers(requests.get(repo).content):
|
||||||
|
pass
|
||||||
|
return split_installer(name)[0]
|
||||||
|
|
||||||
|
|
||||||
|
def installer_name(salt_ver, py_ver='Py2', arch='AMD64'):
|
||||||
|
'''
|
||||||
|
Create an installer file name
|
||||||
|
'''
|
||||||
|
return "Salt-Minion-{}-{}-{}-Setup.exe".format(salt_ver, py_ver, arch)
|
||||||
|
|
||||||
|
|
||||||
|
def latest_installer_name(repo=REPO, **kwargs):
|
||||||
|
'''
|
||||||
|
Fetch the latest installer name
|
||||||
|
'''
|
||||||
|
return installer_name(latest_version(repo), **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
def download_and_verify(fp, name, repo=REPO):
|
||||||
|
'''
|
||||||
|
Download an installer and verify it's contents.
|
||||||
|
'''
|
||||||
|
md5 = "{}.md5".format(name)
|
||||||
|
url = lambda x: "{}/{}".format(repo, x)
|
||||||
|
resp = requests.get(url(md5))
|
||||||
|
if resp.status_code != 200:
|
||||||
|
raise Exception("Unable to fetch installer md5")
|
||||||
|
installer_md5 = resp.text.strip().split()[0].lower()
|
||||||
|
resp = requests.get(url(name), stream=True)
|
||||||
|
if resp.status_code != 200:
|
||||||
|
raise Exception("Unable to fetch installer")
|
||||||
|
md5hsh = hashlib.md5()
|
||||||
|
for chunk in resp.iter_content(chunk_size=1024):
|
||||||
|
md5hsh.update(chunk)
|
||||||
|
fp.write(chunk)
|
||||||
|
if md5hsh.hexdigest() != installer_md5:
|
||||||
|
raise Exception("Installer's hash does not match {} != {}".format(
|
||||||
|
md5hsh.hexdigest(), installer_md5
|
||||||
|
))
|
Loading…
Reference in New Issue
Block a user