def test_tag(self): tag_dict = {"Key": "my_key", "Value": "my_value"} tag = Tag(tag_dict) self.assertEqual(tag.key, "my_key") self.assertEqual(tag.value, "my_value") actual = tag.dump() self.assertEqual(tag_dict, actual)
def create_stacks(self, threads: int = 8): if self.stacks: raise TaskCatException( "Stacker already initialised with stack objects") tests = self._tests_to_list(self.tests) tags = [Tag({"Key": "taskcat-id", "Value": self.uid.hex})] tags += [ Tag(t) for t in self.tags if t.key not in ["taskcat-project-name", "taskcat-test-name", "taskcat-id"] ] fan_out(self._create_stacks_for_test, {"tags": tags}, tests, threads)
def _create_stacks_for_test(self, test, tags, threads: int = 32): stack_name = test.stack_name tags.append(Tag({"Key": "taskcat-project-name", "Value": self.project_name})) tags.append(Tag({"Key": "taskcat-test-name", "Value": test.name})) tags += test.tags partial_kwargs = { "stack_name": stack_name, "template": test.template, "tags": tags, "test_name": test.name, } stacks = fan_out(Stack.create, partial_kwargs, test.regions, threads) self.stacks += stacks
def get_tests(self, templates, regions, buckets, parameters): tests = {} for test_name, test in self.config.tests.items(): region_list = [] tag_list = [] if test.tags: for tag_key, tag_value in test.tags.items(): tag_list.append(Tag({"Key": tag_key, "Value": tag_value})) for region_obj in regions[test_name].values(): region_list.append( TestRegion.from_region_obj( region_obj, buckets[test_name][region_obj.name], parameters[test_name][region_obj.name], ) ) tests[test_name] = TestObj( name=test_name, template_path=self.project_root / test.template, template=templates[test_name], project_root=self.project_root, regions=region_list, tags=tag_list, uid=self.uid, _project_name=self.config.project.name, _shorten_stack_name=self.config.project.shorten_stack_name, ) return tests
def _create_stacks_for_test(self, test, tags, threads: int = 32): prefix = f"{self.stack_name_prefix}-" if self.stack_name_prefix else "" stack_name = "{}{}-{}-{}".format(prefix, self.project_name, test.name, self.uid.hex) tags.append( Tag({ "Key": "taskcat-project-name", "Value": self.project_name })) tags.append(Tag({"Key": "taskcat-test-name", "Value": test.name})) tags += test.tags partial_kwargs = { "stack_name": stack_name, "template": test.template, "tags": tags, "test_name": test.name, } stacks = fan_out(Stack.create, partial_kwargs, test.regions, threads) self.stacks += stacks
def test_filterable_list(self): tags = Tags([Tag({"Key": "my_key", "Value": "my_value"})]) filtered = tags.filter() self.assertEqual(filtered, tags) filtered = tags.filter({"key": "blah"}) self.assertEqual(filtered, []) filtered = tags.filter({"key": "my_key"}) self.assertEqual(filtered, tags) filtered = tags.filter(key="my_key", value="blah") self.assertEqual(filtered, []) filtered = tags.filter(key="my_key", value="my_value") self.assertEqual(filtered, tags)
def run( # noqa: C901 self, project: str = "./", test_names: str = "ALL", regions: str = "ALL", name="", input_file: str = "./.taskcat.yml", ): """ :param project: name of project to install can be a path to a local project,\ a github org/repo, or an AWS Quick Start name :param test_names: comma separated list of tests (specified in .taskcat.yml) to run\ defaults to the 'default' test. Set to 'ALL' to deploy every entry :param regions: comma separated list of regions to test in\ default :param name: stack name to use, if not specified one will be automatically\ generated :param input_file: path to either a taskcat project config file or a CloudFormation template """ if not name: name = generate_name() path = Path(project).resolve() if Path(project).resolve().is_dir(): package_type = "local" elif "/" in project: package_type = "github" else: # assuming it's an AWS Quick Start package_type = "github" project = f"aws-quickstart/quickstart-{project}" if package_type == "github": if project.startswith("https://") or project.startswith("git@"): url = project org, repo = (project.replace(".git", "").replace(":", "/").split("/")[-2:]) else: org, repo = project.split("/") url = f"https://github.com/{org}/{repo}.git" path = Deploy.PKG_CACHE_PATH / org / repo LOG.info(f"fetching git repo {url}") self._git_clone(url, path) self._recurse_submodules(path, url) _extra_tags = [(Tag({"Key": "taskcat-installer", "Value": name}))] Test.run( regions=regions, no_delete=True, project_root=path, test_names=test_names, input_file=input_file, _extra_tags=_extra_tags, )
def test_criteria_matches(self): with self.assertRaises(ValueError) as cm: tag = Tag({"Key": "my_key", "Value": "my_value"}) criteria_matches({"invalid": "blah"}, tag) self.assertEqual( "invalid is not a valid property of <class 'taskcat._dataclasses.Tag'>", str(cm.exception), ) actual = criteria_matches({"key": "blah"}, tag) self.assertEqual(actual, False) actual = criteria_matches({"key": "my_key"}, tag) self.assertEqual(actual, True) actual = criteria_matches({"key": "my_key", "value": "blah"}, tag) self.assertEqual(actual, False) actual = criteria_matches({"key": "my_key", "value": "my_value"}, tag) self.assertEqual(actual, True)
def __init__( # noqa: C901 self, package: str, aws_profile: str = "default", region="default", parameters="", name="", wait=False, ): """ :param package: name of package to install can be a path to a local package, a github org/repo, or an AWS Quick Start name :param aws_profile: aws profile to use for installation :param region: regions to install into, default will use aws cli configured default :param parameters: parameters to pass to the stack, in the format Key=Value,AnotherKey=AnotherValue or providing a path to a json or yaml file containing the parameters :param name: stack name to use, if not specified one will be automatically generated :param wait: if enabled, taskcat will wait for stack to complete before exiting """ LOG.warning("deploy is in alpha feature, use with caution") boto3_cache = Boto3Cache() if not name: name = generate_name() if region == "default": region = boto3_cache.get_default_region(profile_name=aws_profile) path = Path(package).resolve() if Path(package).resolve().is_dir(): package_type = "local" elif "/" in package: package_type = "github" else: # assuming it's an AWS Quick Start package_type = "github" package = f"aws-quickstart/quickstart-{package}" if package_type == "github": if package.startswith("https://") or package.startswith("git@"): url = package org, repo = (package.replace(".git", "").replace(":", "/").split("/")[-2:]) else: org, repo = package.split("/") url = f"https://github.com/{org}/{repo}.git" path = Deploy.PKG_CACHE_PATH / org / repo LOG.info(f"fetching git repo {url}") self._git_clone(url, path) self._recurse_submodules(path, url) config = Config.create( args={"project": { "regions": [region] }}, project_config_path=(path / ".taskcat.yml"), project_root=path, ) # only use one region for test_name in config.config.tests: config.config.tests[ test_name].regions = config.config.project.regions # if there's no test called default, take the 1st in the list if "default" not in config.config.tests: config.config.tests["default"] = config.config.tests[list( config.config.tests.keys())[0]] # until install offers a way to run different "plans" we only need one test for test_name in list(config.config.tests.keys()): if test_name != "default": del config.config.tests[test_name] buckets = config.get_buckets(boto3_cache) stage_in_s3(buckets, config.config.project.name, path) regions = config.get_regions(boto3_cache) templates = config.get_templates(project_root=path) parameters = config.get_rendered_parameters(buckets, regions, templates) tests = config.get_tests(path, templates, regions, buckets, parameters) tags = [Tag({"Key": "taskcat-installer", "Value": name})] stacks = Stacker(config.config.project.name, tests, tags=tags) stacks.create_stacks() LOG.error( f" {stacks.uid.hex}", extra={"nametag": "\x1b[0;30;47m[INSTALL_ID ]\x1b[0m"}, ) LOG.error(f" {name}", extra={"nametag": "\x1b[0;30;47m[INSTALL_NAME]\x1b[0m"}) if wait: LOG.info( f"waiting for stack {stacks.stacks[0].name} to complete in " f"{stacks.stacks[0].region_name}") while stacks.status()["IN_PROGRESS"]: sleep(5) if stacks.status()["FAILED"]: LOG.error("Install failed:") for error in stacks.stacks[0].error_events(): LOG.error(f"{error.logical_id}: {error.status_reason}") raise TaskCatException("Stack creation failed")