1""" 2 :codeauthor: Nicole Thomas <nicole@saltstack.com> 3""" 4 5 6import os 7 8import salt.utils.cloud 9import salt.utils.files 10import salt.utils.yaml 11import yaml 12from tests.integration.cloud.helpers.cloud_test_base import CloudTest 13from tests.support import win_installer 14from tests.support.runtests import RUNTIME_VARS 15from tests.support.unit import skipIf 16 17HAS_WINRM = salt.utils.cloud.HAS_WINRM and salt.utils.cloud.HAS_SMB 18# THis test needs a longer timeout than other cloud tests 19TIMEOUT = 1200 20 21 22class EC2Test(CloudTest): 23 """ 24 Integration tests for the EC2 cloud provider in Salt-Cloud 25 """ 26 27 PROVIDER = "ec2" 28 REQUIRED_PROVIDER_CONFIG_ITEMS = ("id", "key", "keyname", "private_key", "location") 29 30 @staticmethod 31 def __fetch_installer(): 32 # Determine the downloaded installer name by searching the files 33 # directory for the first file that looks like an installer. 34 for path, dirs, files in os.walk(RUNTIME_VARS.FILES): 35 for file in files: 36 if file.startswith(win_installer.PREFIX): 37 return file 38 39 # If the installer wasn't found in the previous steps, download the latest Windows installer executable 40 name = win_installer.latest_installer_name() 41 path = os.path.join(RUNTIME_VARS.FILES, name) 42 with salt.utils.files.fopen(path, "wb") as fp: 43 win_installer.download_and_verify(fp, name) 44 return name 45 46 @property 47 def installer(self): 48 """ 49 Make sure the testing environment has a Windows installer executable. 50 """ 51 if not hasattr(self, "_installer"): 52 self._installer = self.__fetch_installer() 53 return self._installer 54 55 def setUp(self): 56 """ 57 Sets up the test requirements 58 """ 59 group_or_subnet = self.provider_config.get("securitygroup") 60 if not group_or_subnet: 61 group_or_subnet = self.provider_config.get("subnetid") 62 63 if not group_or_subnet: 64 self.skipTest( 65 "securitygroup or subnetid missing for {} config".format(self.PROVIDER) 66 ) 67 68 super().setUp() 69 70 def override_profile_config(self, name, data): 71 conf_path = os.path.join( 72 RUNTIME_VARS.TMP_CONF_DIR, "cloud.profiles.d", "ec2.conf" 73 ) 74 with salt.utils.files.fopen(conf_path, "r") as fp: 75 conf = yaml.safe_load(fp) 76 conf[name].update(data) 77 with salt.utils.files.fopen(conf_path, "w") as fp: 78 salt.utils.yaml.safe_dump(conf, fp) 79 80 def copy_file(self, name): 81 """ 82 Copy a file from tests/integration/files to a test's temporary 83 configuration directory. The path to the file which is created will be 84 returned. 85 """ 86 src = os.path.join(RUNTIME_VARS.FILES, name) 87 dst = os.path.join(RUNTIME_VARS.TMP_CONF_DIR, name) 88 with salt.utils.files.fopen(src, "rb") as sfp: 89 with salt.utils.files.fopen(dst, "wb") as dfp: 90 dfp.write(sfp.read()) 91 return dst 92 93 def _test_instance(self, profile, debug): 94 """ 95 Tests creating and deleting an instance on EC2 (classic) 96 """ 97 98 # create the instance 99 cmd = ["-p", profile] 100 if debug: 101 cmd.extend(["-l", "debug"]) 102 cmd.append(self.instance_name) 103 ret_val = self.run_cloud(" ".join(cmd), timeout=TIMEOUT) 104 105 # check if instance returned with salt installed 106 self.assertInstanceExists(ret_val) 107 ipv6Address_present = False 108 for each in ret_val: 109 if "ipv6Address:" in each: 110 ipv6Address_present = True 111 assert ipv6Address_present 112 113 self.assertDestroyInstance() 114 115 def test_instance_rename(self): 116 """ 117 Tests creating and renaming an instance on EC2 (classic) 118 """ 119 # create the instance 120 ret_val = self.run_cloud( 121 "-p ec2-test {} --no-deploy".format(self.instance_name), timeout=TIMEOUT 122 ) 123 # check if instance returned 124 self.assertInstanceExists(ret_val) 125 126 changed_name = self.instance_name + "-changed" 127 128 rename_result = self.run_cloud( 129 "-a rename {} newname={} --assume-yes".format( 130 self.instance_name, changed_name 131 ), 132 timeout=TIMEOUT, 133 ) 134 self.assertFalse( 135 self._instance_exists(), 136 "Instance wasn't renamed: |\n{}".format(rename_result), 137 ) 138 self.assertInstanceExists(instance_name=changed_name) 139 140 self.assertDestroyInstance(changed_name) 141 142 def test_instance(self): 143 """ 144 Tests creating and deleting an instance on EC2 (classic) 145 """ 146 self._test_instance("ec2-test", debug=False) 147 148 def test_win2012r2_psexec(self): 149 """ 150 Tests creating and deleting a Windows 2012r2instance on EC2 using 151 psexec (classic) 152 """ 153 # TODO: psexec calls hang and the test fails by timing out. The same 154 # same calls succeed when run outside of the test environment. 155 # FIXME? Does this override need to be undone at the end of the test? 156 self.override_profile_config( 157 "ec2-win2012r2-test", 158 { 159 "use_winrm": False, 160 "userdata_file": self.copy_file("windows-firewall-winexe.ps1"), 161 "win_installer": self.copy_file(self.installer), 162 }, 163 ) 164 self._test_instance("ec2-win2012r2-test", debug=True) 165 166 @skipIf(not HAS_WINRM, "Skip when winrm dependencies are missing") 167 def test_win2012r2_winrm(self): 168 """ 169 Tests creating and deleting a Windows 2012r2 instance on EC2 using 170 winrm (classic) 171 """ 172 self.override_profile_config( 173 "ec2-win2012r2-test", 174 { 175 "userdata_file": self.copy_file("windows-firewall.ps1"), 176 "win_installer": self.copy_file(self.installer), 177 "winrm_ssl_verify": False, 178 "use_winrm": True, 179 }, 180 ) 181 self._test_instance("ec2-win2012r2-test", debug=True) 182 183 def test_win2016_psexec(self): 184 """ 185 Tests creating and deleting a Windows 2016 instance on EC2 using winrm 186 (classic) 187 """ 188 # TODO: winexe calls hang and the test fails by timing out. The 189 # same calls succeed when run outside of the test environment. 190 self.override_profile_config( 191 "ec2-win2016-test", 192 { 193 "use_winrm": False, 194 "userdata_file": self.copy_file("windows-firewall-winexe.ps1"), 195 "win_installer": self.copy_file(self.installer), 196 }, 197 ) 198 self._test_instance("ec2-win2016-test", debug=True) 199 200 @skipIf(not HAS_WINRM, "Skip when winrm dependencies are missing") 201 def test_win2016_winrm(self): 202 """ 203 Tests creating and deleting a Windows 2016 instance on EC2 using winrm 204 (classic) 205 """ 206 self.override_profile_config( 207 "ec2-win2016-test", 208 { 209 "userdata_file": self.copy_file("windows-firewall.ps1"), 210 "win_installer": self.copy_file(self.installer), 211 "winrm_ssl_verify": False, 212 "use_winrm": True, 213 }, 214 ) 215 self._test_instance("ec2-win2016-test", debug=True) 216