3 =\)  @s&ddlmZddlZddlZddlZddlZddlZddlZddlZddl Z ddl Z ddl Z ddl Z ddl Z ddlZddlZddlZddlZddlmZddlmZddlmZddlmZddlmZddlmZdd lmZdd l m!Z!dd l"m#Z#dd l$m%Z%dd l&m'Z'ddl(m)Z)ddl m*Z*m+Z+ddl,m-Z-yedj.j/ddZ0dZ1Wn4e'k rjYne2k rdZ0dZ1YnXe0Z.ej3dj4Z5e6e j7Z8ej9dZ:e:j;ej<ddZ=ddZ>d'ddZ?Gddde@ZAGd d!d!e@ZBGd"d#d#ejCZDd$d%ZEeFd&krneEdS)()print_functionN)RawTextHelpFormatter)requests)get_distribution)Reaper) ClientFactory)PrintMsg) ReportBuilder) CommonTools) CfnLogTools)CfnResourceTools)TaskCatException)S3Sync)exit0param_list_to_dict)ParamGentaskcatz.0.z&[local source] no pip module installedzdENhVA==cCstj|jddS)Ninfoversion)rgetjson)urlrh/private/var/folders/pf/wv4htv3x0qs2c2mp0dnn0kchsvlck3/T/pip-install-emcbgzcf/taskcat/taskcat/stacker.pyget_pip_versionSsrcCstS)N) __version__rrrrget_installed_versionWsrTc Csj|sdj|}g}xRtj|ddD]@\}}}x4|D],}tjj||}||kr2d|kr2|j|q2Wq"W|S)a0 Given a start location and a string value, this function returns a list of file paths containing the given string value, down in the directory structure from the start location. :param start_location: directory from where to start looking for the file :param map_string: value to match in the file path :param partial_match: (bool) Turn on partial matching. : Ex: 'foo' matches 'foo' and 'foo.old'. Defaults true. False adds a '/' to the end of the string. :return: list of file paths containing the given value. z{}/F)topdownz.git)formatoswalkpathjoinappend) Zstart_locationZ map_stringZ partial_matchZfs_mapZfs_pathdirsfilelistZfs_fileZfs_path_to_filerrrbuildmap[s   r(c@s4eZdZddZddZddZddZd d Zd S) TestDatacCsd|_g|_dS)N)_TestData__test_name_TestData__test_stacks)selfrrr__init__zszTestData.__init__cCs ||_dS)N)r*)r,namerrr set_test_name~szTestData.set_test_namecCs|jS)N)r*)r,rrr get_test_nameszTestData.get_test_namecCs|jS)N)r+)r,rrrget_test_stacksszTestData.get_test_stackscCs|jj|dS)N)r+r%)r,stackrrradd_test_stackszTestData.add_test_stackN)__name__ __module__ __qualname__r-r/r0r1r3rrrrr)ys r)c@sdeZdZdddZddZddZdd Zd d Zd d ZddZ ddZ ddZ ddZ ddZ ddZddZddZddZd d!Zd"d#Zd$d%Zd&d'Zd(d)Zd*d+Zd,d-Zd.d/Zd0d1Zd2d3Zd4d5Zd6d7Zd8d9Zd:d;Zdd?Z!d@dAZ"dBdCZ#dDdEZ$dFdGZ%dHdIZ&dJdKZ'dLdMZ(dNdOZ)dPdQZ*dRdSZ+dTdUZ,dVdWZ-dXdYZ.dZd[Z/d\d]Z0d^d_Z1d`daZ2dbdcZ3dddeZ4dfdgZ5e6dhdiZ7djdkZ8dldmZ9dndoZ:dpdqZ;drdsZdxdyZ?dzd{Z@d|d}ZAdddZBdddZCdddZDddZEddZFddZGddZHeIddZJe6dddZKdddZLd~S)TaskCat [taskcat]cCs.dj|tjtj|_d|_d|_d|_d|_g|_ d|_ d|_ g|_ d|_ d|_d|_d|_d|_d|_d|_d|_d|_d|_d|_d|_d|_d|_d|_d|_d|_i|_d|_d|_ d|_!d|_"d|_#t$t%d|_&i|_'d|_(g|_)d|_*d|_+t,|_-d|_.d|_/d|_0d|_1d|_2g|_3d|_4dS) Nz {1}{0}{2}Fz taskcat.ymlnT)logger?)5r rZ name_color rst_colornametag _project_name _project_pathownerbanner capabilitiesverboseconfig test_regions3bucket s3bucket_type template_pathparameter_pathdefault_region_template_file_template_type_parameter_fileZ_parameter_path ddb_table_enable_dynamodbZ _termsize_strict_syntax_jsonZ_banner _auth_modeZ_report _use_global _parameters run_cleanuppublic_s3_bucket_aws_access_key_aws_secret_key _boto_profilerr; _boto_client _key_url_mapretain_if_failedtags stack_prefix template_datarr s3_url_prefix upload_only_max_bucket_name_lengthlambda_build_onlyZone_or_more_tests_failedexclude enable_sig_v2)r,r>rrrr-s\ zTaskCat.__init__cCs ||_dS)N)r?)r, project_namerrrset_project_nameszTaskCat.set_project_namecCs|jS)N)r?)r,rrrget_project_nameszTaskCat.get_project_namecCs|jS)N)r@)r,rrrget_project_pathszTaskCat.get_project_pathcCs ||_dS)N)r@)r,r#rrrset_project_pathszTaskCat.set_project_pathcCs ||_dS)N)rA)r,rArrr set_ownerszTaskCat.set_ownercCs|jS)N)rA)r,rrr get_ownerszTaskCat.get_ownercCs|jj|dS)N)rCr%)r,Zabilityrrrset_capabilitiesszTaskCat.set_capabilitiescCs|jS)N)rC)r,rrrget_capabilitiesszTaskCat.get_capabilitiescCs ||_dS)N)rG)r,bucketrrr set_s3bucketszTaskCat.set_s3bucketcCs t|jS)N)strrG)r,rrr get_s3bucketszTaskCat.get_s3bucketcCs ||_dS)N)rH)r,rorrrset_s3bucket_typeszTaskCat.set_s3bucket_typecCs t|jS)N)rqrH)r,rrrget_s3bucket_typeszTaskCat.get_s3bucket_typecCs,tjj|r||_ntd|tddS)NzCannot locate file %sr)r!r#isfilerEprintexit)r, config_ymlrrr set_configs  zTaskCat.set_configcCs|jS)N)rE)r,rrr get_configszTaskCat.get_configcCs|jS)N)rQ)r,rrrget_strict_syntax_jsonszTaskCat.get_strict_syntax_jsoncCs ||_dS)N)rQ)r,valuerrrset_strict_syntax_jsonszTaskCat.set_strict_syntax_jsoncCs|jS)N)rL)r,rrrget_template_fileszTaskCat.get_template_filecCs ||_dS)N)rL)r,templaterrrset_template_fileszTaskCat.set_template_filecCs|jS)N)rM)r,rrrget_template_typeszTaskCat.get_template_typecCs ||_dS)N)rM)r,Z template_typerrrset_template_type szTaskCat.set_template_typecCs ||_dS)N)rN)r, parameterrrrset_parameter_file szTaskCat.set_parameter_filecCs|jS)N)rd)r,rrr get_excludeszTaskCat.get_excludecCs|jS)N)rN)r,rrrget_parameter_fileszTaskCat.get_parameter_filecCs ||_dS)N)rJ)r,rrrrset_parameter_pathszTaskCat.set_parameter_pathcCs|jS)N)rJ)r,rrrget_parameter_pathszTaskCat.get_parameter_pathc$CsZttjdg}djtjjdd}tjj|rt|V}yt j |j }Wnt k rjt dYnXttjdttjt|WdQRX|j|dj|j}y\t|d }|j }WdQRXt j |}|j|ttjd j|ttjt|WnVt k r(t d Yn:t k r>Yn$tk r`} zWYdd} ~ XnXt|} |j} x`|D]X} xP| D]H} | d }|| jkr| |}| ||<nttjd j||jqWqxW|j}d}||jkrV|| krV| |}||d}||krV|dkrVttjdj||ttjdj||||d<|S)av This function searches for ~/.aws/taskcat_global_override.json, then /ci/taskcat_project_override.json, in that order. Keys defined in either of these files will override Keys defined in /ci/*.json or in the template parameters. :param original_keys: json object derived from Parameter Input JSON in /ci/ z|Processing Overridesz {}/.aws/{}~ztaskcat_global_override.jsonz/Unable to parse JSON (taskcat global overrides)z6Values loaded from ~/.aws/taskcat_global_override.jsonNz#{}/ci/taskcat_project_override.jsonrzValues loaded from {}z0Unable to parse JSON (taskcat project overrides)Z ParameterKeyzYCannot apply overrides for the [{}] Parameter. You did not include this parameter in [{}]ZQSS3BucketNameZParameterValuez$[taskcat_autobucket]zInconsistency detected between S3 Bucket Name provided in the TaskCat Config [{}] and QSS3BucketName Parameter Value within the template: [{}]z+Setting the value of QSS3BucketName to [{}])rvrINFOr r!r# expanduserruopenrloadsread ValueErrorr DEBUGrqr%ri Exceptionrextract_template_parameterskeysrrr)r,Z original_keysZdict_squash_listZ_homedir_override_file_pathfZ_homedir_override_jsonZlocal_override_file_pathcontent_objeZ param_indexZtemplate_paramsoverrideZ override_pdkeyidx bucket_nameZ_knZ_knidxZparam_bucket_namerrrget_param_includess`           &    zTaskCat.get_param_includescCs ||_dS)N)rI)r,rrrrset_template_pathcszTaskCat.set_template_pathcCs|jS)N)rI)r,rrrget_template_pathfszTaskCat.get_template_pathcCs||j|<dS)N)rT)r,rvalrrr set_parameteriszTaskCat.set_parametercCs |j|S)N)rT)r,rrrr get_parameterlszTaskCat.get_parametercCs ||_dS)N)rO)r,rOrrrset_dynamodb_tableoszTaskCat.set_dynamodb_tablecCs|jS)N)Zddbtable)r,rrrget_dynamodb_tablerszTaskCat.get_dynamodb_tablecCs ||_dS)N)rK)r,regionrrrset_default_regionuszTaskCat.set_default_regioncCs|jS)N)rK)r,rrrget_default_regionxszTaskCat.get_default_regioncCs|jS)N)rF)r,rrrget_test_region{szTaskCat.get_test_regioncCs$g|_x|D]}|jj|q WdS)N)rFr%)r,Z region_listrrrrset_test_region~s zTaskCat.set_test_regioncCs ||_dS)N)rU)r,Z cleanup_valuerrr set_docleanupszTaskCat.set_docleanupcCs|jS)N)rU)r,rrr get_docleanupszTaskCat.get_docleanupc Cs|jr d}nd}|jjd|jdd}d|djkr|j|dd|jdttj d |j t |j |j krt d j|j y|j|j d }Wn>|jjk rt d j|j Yntk rYnXnd |jd|jdtdd}|j}t ||j kr.|d|j }|jrtdjtj ||j|jdkrn|j||d}n|j||d|jid}|jdnt d|j|dddkrttj d||j|n^tdjtj ||j|j||d|jid}|dddkr0ttj d||j||jrL|j|d|jid|js|ttj d|d|}|j||d x:|jD].}tjj|rt j!j"|n t j#j"|qWt ||j |j|j$|d!|j%d"|j|_&|j'rt(d#dS)$a Upload templates and other artifacts to s3. This function creates the s3 bucket with name provided in the config yml file. If no bucket name provided, it creates the s3 bucket using project name provided in config yml file. And uploads the templates and other artifacts to the s3 bucket. :param taskcat_cfg: Taskcat configuration provided in yml file z public-readzbucket-owner-reads3T)rs3v4rGglobaldefinedzStaging Bucket => z;The bucket name you provided is greater than {} characters.)Bucketz5The bucket you provided [{}] does not exist. Exiting.ztaskcat--Nz{0}Creating bucket {1} in {2}z us-east-1)ACLrLocationConstraint)rrZCreateBucketConfigurationautozDefault_region = ZResponseMetadataZHTTPStatusCodezStaging Bucket => [%s]ZTagSet)rZTaggingz&Enforcing sigv4 requests for bucket %sa{ "Version": "2012-10-17", "Statement": [ { "Sid": "Test", "Effect": "Deny", "Principal": "*", "Action": "s3:*", "Resource": "arn:aws:s3:::%s/*", "Condition": { "StringEquals": { "s3:signatureversion": "AWS" } } } ] } )rPolicyzhttps:///zUpload completed successfully))rVrZrrrrprsrvrrrrlenrbr r list_objects exceptions NoSuchBucketrr^rhjobidlowerZ create_bucketr]Zput_bucket_taggingreZput_bucket_policyrr!r#isdirrZexclude_path_prefixesr%Z exclude_filesriget_s3_hostnamer`rar) r, taskcat_cfgZbucket_or_object_acl s3_client_Z auto_bucketresponsepolicyrdrrr stage_in_s3sp   &     zTaskCat.stage_in_s3cCsF|jrBttjdj|j|jjd|jdd}|j |jdddS)NzThe staging bucket [{}] should be only required during cfn bootstrapping. Removing public permission as they are no longer needed!rT)rrprivate)rr) rVrvrrr rGrZrrZput_bucket_acl)r,rrrrremove_public_acl_from_bucketsz%TaskCat.remove_public_acl_from_bucketc Cs|jjd|jdd}y|j||d}Wn>tk r>Yn*tk rftdjtj ||YnX|dj j dj }|S)z Returns the content of an object, given the bucket name and the key of the object :param bucket: Bucket name :param object_key: Key of the object :return: Content of the object rT)rr)rKeyz){} Attempted to fetch Bucket: {}, Key: {}ZBodyzutf-8) rZrrZ get_objectr rrvr rERRORrdecodestrip)r,roZ object_keyrZ dict_objectrrrr get_contents zTaskCat.get_contentcCs0|jrtj|}|jS|j|}|j|j|S)z Returns S3 object. - If --public-s3-bucket is passed, returns via the requests library. - If not, does an S3 API call. :param url: URL of the S3 object to return. :return: Data of the s3 object )rVrrtextr[rrr)r,rpayloadrrrrget_s3contents s   zTaskCat.get_s3contentsc Cs"t|d}|j}WdQRX|S)z Returns local file contents as a string. :param path: URL of the S3 object to return. :return: file contents rN)rr)r,r#rdatarrr get_contentss zTaskCat.get_contentscCs\|jjd|jdd}|j|jd}|ddk rJdj|dd|j}nd j|j}|S) zT Returns S3 hostname of target bucket :return: S3 hostname rT)rr)rrNzs3-{0}.{1}/{2}z amazonaws.comz{0}.s3.amazonaws.com)rZrrZget_bucket_locationrrr )r,rZbucket_locationhostnamerrrr&s   zTaskCat.get_s3_hostnamecCsg}x|djD]}d|krd}y:t|ddx$|ddD]}|j|d|_qBWWqtk r}z*ttjd|ttjd|WYdd}~XqXqW|S)z Returns a list of regions defined under global region in the yml config file. :param yamlcfg: Content of the yml config file :return: List of regions rrregionsTzNo regions defined in [%s]:zPlease correct region defs[%s]:N)riterr%rS TypeErrorrvrr)r,ZyamlcfgZ g_regionsr namespacerrrrrget_global_region5s (zTaskCat.get_global_regioncCs d|jkr|jdjSiSdS)z Returns a dictionary of the parameters in the template entrypoint, if it exist. Otherwise, return empty {} dictionary if there are no parameters in the template. :return: list of parameters for the template. ParametersN)r_r)r,rrrrKs z#TaskCat.extract_template_parametersc Cs|j|j|x|D]}t|jd||j||y|jrZttjd|j|j j d|jd}|j |j d|j d}ttjd|j d|kr|d}ttjd tj|nttjd |j |jrtj|d d dd}ttjdt|Wqtk r*Yqtk r}z\|jrVttjt|ttjd|j ttjd|jtd|j WYdd}~XqXqWtddS)z Returns TRUE if all the template files are valid, otherwise FALSE. :param taskcat_cfg: TaskCat config object :param test_list: List of tests :return: TRUE if templates are valid, else FALSE z :Validate Template in test[%s]zDefault region [%s]cloudformation)rz /templates/) TemplateURLzValidated [%s] DescriptionzDescription [%s]z9Please include a top-level description for template: [%s]r ,: )indent separatorsz Parameters:zCannot validate %sz-Deleting any automatically-created buckets...N T)rr)rrrvr> define_testsrDrrrrZrvalidate_templater`r~PASSrtextwrapfillrdumpsr rrqZFAILdelete_autobucket) r,r test_listtestcfnresultZ cfn_resultZ cfn_paramsrrrrrWs<   &zTaskCat.validate_templatecCst||j|j|ddjS)a Given a cloudformation input parameter file as JSON, this function generates the values for the parameters indicated by $[] appropriately, replaces $[] with new value and return the updated JSON. :param region: :param s_parms: Cloudformation template input parameter file as JSON :return: Input parameter file as JSON with $[] replaced with generated values T)Z param_listrZ boto_clientrrD)rrrrZresults)r,s_parmsrrrrgenerate_input_param_valuessEz#TaskCat.generate_input_param_valuescCsbg}|jd|jdx|D]}t}|j|tdjtjtj|tjt t }|d|d|dt dd}|j ||xP|j D]B} ttjd| y|jjd| d } |j|jd |j} tj| } |j| } | r| } |j| | }|jrttjd | ttjd |ttjd ttjd|jttjd|jttjdttjdt |j|jdkrttj|ddd,dy2| j|d|j||j|jd}ttjdWn| jj k r}zt |j!dsttjd| j"||j||jd|dd}|d}| j#d }|j$|d!d"d#d$| j%|d%d&|d&i}WYdd}~XnX|j&|Wqt'k rYqt(k r}zWYdd}~XqXqW|j)|q Wtd'xj|D]b}xZ|j*D]N}td(j|j+tjtjtd)jtjtj|j,t |d&j-d*d+tjqWqW|S)-aX This function creates CloudFormation stack for the given tests. :param taskcat_cfg: TaskCat config as yaml object :param test_list: List of tests :param sprefix: Special prefix as string. Purpose of this param is to use it for tagging the stack. :return: List of TestData objects ZCAPABILITY_AUTO_EXPANDZCAPABILITY_NAMED_IAMz${0}{1}|PREPARING TO LAUNCH => {2}{3}rNrz#Preparing to launch in region [%s] r)rz/ci/z"Creating Boto Connection region=%sz StackName=zDisableRollback=TruezTemplateURL=%szCapabilities=%sz Parameters:zTags:%srTrr: ) sort_keysrr) StackNameZDisableRollbackrr CapabilitiesZTagsz"|CFN Execution mode [create_stack]z4cannot be used with templates containing Transforms.z |CFN Execution mode [change_set]ZCREATEz-cs)rrrrZ ChangeSetType ChangeSetNameZIdZchange_set_create_complete )ZDelayZ MaxAttempts)rZ WaiterConfig)rStackIdrz{} |{}LAUNCHING STACKS{}z {} {}{} {} {}z:stackr)rr).rmr)r/rvr rrheaderr=rqsigrrrrZrrrirrrrrrDrrrnr]rrZ create_stackrZ ClientErrorendswithZcreate_change_set get_waiterwaitZexecute_change_setr3r rr%r1r>r0split)r,rrZsprefix testdata_listrZtestdataZsnameZ stacknamerrZ s_parmsdatarZs_include_paramsZj_params stackdatarZ stack_cs_dataZchange_set_namewaiterr2rrr stackcreates    $         zTaskCat.stackcreatecCsx|D]}|j||t|jd||jrDttjd|j|j|jd|j }|j |}|jrttjd||rttj d|j qttjd|j t d|j qWdS) a  This function validates the parameters file of the CloudFormation template. :param taskcat_cfg: TaskCat config yaml object :param test_list: List of tests :return: TRUPrintMsg.ERROR if the parameters file is valid, else FALSE z! |Validate JSON input in test[%s]zparameter_path = %sz/ci/zjsonstatus = %szValidated [%s]zparameter_file = %szCannot validate %sT) rrvr>rDrrrrrir check_jsonrr )r,rrrZ inputparmsZ jsonstatusrrrvalidate_parameters5s   zTaskCat.validate_parameterscCs&|j|}|rt|jStdSdS)z Returns the matching string. :param re_object: Regex object :param data_line: String to be searched :return: Matching String if found, otherwise return 'Not-found' z Not-foundN)searchrqgroup)Z re_objectZ data_lineZsgrrrregxfindRs  zTaskCat.regxfindc Cst|j}|d}|d}g}|jjd|d}yx|j|d}xf|dD]Z}|j||j||j|jd|jddks|jdd kr|jd qH|jd qHWWnPtk rYn<tk r|j||j||jd |jd YnX|S) aZ Given the stack id, this function returns the status of the stack as a list with stack name, region, and status as list items, in the respective order. :param stack_id: CloudFormation stack id :return: List containing the stack name, region and stack status in the respective order. r stack_namer)r)rZStacksZ StackStatusZCREATE_IN_PROGRESSDELETE_IN_PROGRESSrr STACK_DELETED)r parse_stack_inforZrZdescribe_stacksr%r r) r,Zstack_idrrrZ test_inforZ test_queryrrrr stackcheckcs.        zTaskCat.stackcheckcCstjd|jd}yP|j|dddgdddgddd d }td j||jjjd j |d |St k rxYnXt k r}z<|rtdj||j |}|jjjd j |d |SWYdd}~XnXdS)z :param table_name: Creates table if it does not exist. Waits for the table to become available :return: DynamoDB object dynamodb) region_namezjob-nameHASH) AttributeNameZKeyTypeS)rZ AttributeType)ZReadCapacityUnitsZWriteCapacityUnits) TableNameZ KeySchemaZAttributeDefinitionsZProvisionedThroughputzCreating new [{}]Z table_exists)rzAdding to existing [{}]N) boto3resourcerZ create_tablervr metaclientrrr rZTable)r,Z table_namer tableZnotablerrrdb_initprojects*  zTaskCat.db_initprojectc Cs(|j||||||tdddddS)Nr)zjob-namezlast-runrrAz test-historyz job-statusz test-outputs)ZItem)Zput_itemr)r,r time_stamprZjob_nameZ log_grouprAZ job_statusrrrdb_itemszTaskCat.db_itemcCs ||_dS)N)rP)r,enablerrrenable_dynamodb_reportingsz!TaskCat.enable_dynamodb_reportingc CsPd}tdx<|dkrJd}ttjdjtjdjddjdd tjtjjj d }x|D]}x|j D]}|j t |d }|d |}tjd j|djd|djd|dtj tj} t| |jr|j|j} ddg} |d| kr|j| ||d|jd|j|d|d|d<|}tj|qnWq`WtdqWdS)aW Given a list of TestData objects, this function checks the stack status of each CloudFormation stack and updates the corresponding TestData object with the status. :param testdata_list: List of TestData object :param speed: Interval (in seconds) in which the status has to be checked in loop rrrz{}{} {} [{}]{}z AWS REGIONzCLOUDFORMATION STACK STATUSzCLOUDFORMATION STACK NAMEz%Y-%m-%d %H:%M:%Srz{3}{0} {1} [{2}]{4}r r zlog group stubstatusN)rvrrr rljustr=datetimenowstrftimer1r rq highlightrPrrhrr0rltimesleep) r,rspeedZ active_testsZcurrent_active_testsrrr2Z stackqueryZlogsrZ skip_statusrrrget_stackstatussL          zTaskCat.get_stackstatuscCs|j|j}|jr,ttjdt||rjtdj|jtj tj |j ||j |||j |nttjdj|dS)a This function deletes the CloudFormation stacks of the given tests. :param testdata_list: List of TestData objects :param speed: Interval (in seconds) in which the status has to be checked while deleting the stacks. zclean-up = %s z{} |CLEANUP STACKS{}z)[Retaining Stacks (Cleanup is set to {0}]N)rrrDrvrrrqr r>rr= stackdeleter+ deep_cleanupr)r,rr*Z docleanuprrrcleanups    zTaskCat.cleanupc Cs@x0|D]&}g}x.|jD]"}t|ddkr|j|dqWt|dkr^ttjdqttjdt|dj}|d}t j j |d}t |}t |jj||} |jrttjd xd| D]\} ttjd | d x@| d D]4} ttjd jd| jdd| jdd| jdqWqW|j| qW|jdS)z This function deletes the AWS resources which were not deleted by deleting CloudFormation stacks. :param testdata_list: List of TestData objects r"Z DELETE_FAILEDrrz [%s]z|Project => [%s]z|Template => [%s]z|Parameter => [%s]z|TemplateType => [%s]rz|Defined Regions:z - [%s]z|Global Regions:z(Completed) acquisition of [%s]r)-rrDrvrrrrrUr rkrrrr`r~rrrrquitrrrirrrQrrr_ check_cfnyamlcfnlintrcfn_yamlmulti_constructor MarkedLoaderadd_multi_constructorget_single_datarrrhrrlistrrr)r,ZyamlcrZtdefstpnoZ cleanupstackrIrJZ cfntemplateZ m_constructorloaderrZlist_oZglobal_regionsrrrrus                 zTaskCat.define_testsNcCsdy.tj|}|jr,|s,ttj|ddddWn0tk r^}z|rPtt|dSd}~XnXdS) aC This function validates the given JSON. :param jsonin: Json object to be validated :param quiet: Optional value, if set True suppress verbose output :param strict: Optional value, Display errors and exit :return: TRUPrintMsg.ERROR if given Json is valid, FALSE otherwise. Trr: )rrrFN)rrM)rrrDrvrrr rq)r,Zjsoninr;r<parmsrrrrrs   zTaskCat.check_jsoncCs^y&tjt}|jr$|s$ttj|Wn2tjk rX}z|rJtt|dSd}~XnXdS)aC This function validates the given YAML. :param yamlin: Yaml object to be validated :param quiet: Optional value, if set True suppress verbose output :param strict: Optional value, Display errors and exit :return: TRUPrintMsg.ERROR if given yaml is valid, FALSE otherwise. FNT)r= safe_loadrDrvZ safe_dumpZ YAMLErrorr rq)r,yamlinr;r<rNrrrr check_yamls   zTaskCat.check_yamlcCsyFT) rArrBrDrErCrDrvrFr rrq)r,rPr;r<rLrrrrr@ s  zTaskCat.check_cfnyamlcCsztd|jtj|j|jd|jd|jrd|_|j|_yP|j j d|j|jd}|j j d}t|j d|t|j d |jWnVt k rYnBtk r}z&|jrttjt|t d WYdd}~XnXn|jo|jrd |_|j|_|j|_yT|j j d|j|j|jd }|j j d}t|j d|t|j d |jWnbt k rxYnLtk r}z.ttjd |jrttjt|WYdd}~XnXnd|_yL|j j d|jd}|j j d}t|j d|t|j d |jWn\t k r0YnFtk rt}z(|jr\ttjt|t dWYdd}~XnXdS)a[ This function reads the AWS credentials from various sources to ensure that the client has right credentials defined to successfully run TaskCat against an AWS account. :param args: Command line arguments for AWS credentials. It could be either profile name, access key and secret key or none. rN)rZprofilests)Z profile_namerZAccountz :AWS AccountNumber: [%s]z :Authenticated via: [%s]z,Credential Error - Please check you profile!r)Zaws_access_key_idZaws_secret_access_keyrz)Credential Error - Please check you keys! environmentz@Credential Error - Please check your boto environment variable !)rvrrraws_access_keyaws_secret_key boto_profilerRrYrZrZget_caller_identityr>r rrDrrrqrWrXr)r,argsZ sts_clientaccountrrrr aws_api_init'sb   & zTaskCat.aws_api_initc Cstdg}dddg}ddg}ytjj|r&t|jdj|t|d}tj|j }x.|D]&}||d j krzqdt d ||qdWx|d j D]z}|j |t|jd |xX|d |j D]D} x>|D]6}||d |j krqtd ||t d| qWqWqWWdQRXn t d|Wn`t k rLYnJt k r} z,|jrxttjt| t d|WYdd} ~ XnX|S)zi This function validates the given yaml file. :param yaml_file: Yaml file name rr:rArr8r9z :Reading Config form: {0}rrzglobal:%s missing from r7z |Queing test => %s zNo key %s in testzWhile inspecting: NzCannot open [%s]z'config.yml [%s] is not formatted well!!)rvr!r#rur>r rr=rOrrr r%rrDrrrq) r,Z yaml_fileZ run_testsZrequired_global_keysZrequired_test_parametersZ checkyamlZcfg_ymlrrrNrrrr validate_yamlfsB    $zTaskCat.validate_yamlc Csi}ttjdx|D]}x|jD]}t|dj}t|jjt |dt |d||d<d}dj ||d|dd|}t |d} | j t t j|d dd | jq&WqWd S)z This function collects the AWS resources information created by the CloudFormation stack for generating the report. :param testdata_list: List of TestData object :param logpath: Log file path z(Collecting Resources)rrrz.txtz {}/{}-{}-{}{}r/wr: )rrN)rr])rvrrr1r r r rZ get_resourcesrqr rwriterrclose) r,rZlogpathrrr2Z stackinfo extensionZ test_logpathfilerrrcollect_resourcess,      zTaskCat.collect_resourcescCsd}ytj|Wn2tk r(Yntk rDtj|YnXtdj|jtj tj ttj d||d|}t |j }|j||t|||j|j |}|jdS)z This function creates the test report. :param testdata_list: List of TestData objects :param filename: Report file name :return: Ztaskcat_outputsz{} |GENERATING REPORTS{}zCreating report in [%s]rN)r!statr rmkdirrvr r>rrr=rr rZZ createcfnlogsr rZgenerate_report)r,rfilenameZ o_directoryZdashboard_filenameZcfn_logsZ cfn_reportrrr createreports   zTaskCat.createreportcCstjdddtd}|jddtdd|jd d td d|jd d tdd|jddtdd|jddddd|jddddd|jddddd|jddddd|jd d!td"d|jd#d$td%d&d'|jd(d)dd*d|jd+d,dd-d|jd.d/dd0d|jd1d2dd3d|jd4d5d6d7d|jd8dd9d|j}ttj d:krd|j t |j t |jr|t tt |jrd;|_|jrd;|_|jrd;|_|js|jd<t |j td<y |j|_Wntk rYnXy|jdk r|j|_Wntk rYnXtjd=j|js|j|_|jrRd;|_|jr`d?|_|j dk r|j!dk s|j"dk r|jdCt |j tdD|j#rd;|_#|j$r|jr|jdBt |j tdBd;|_%|S)ENzx Multi-Region CloudFormation Test Deployment Tool) For more info see: http://taskcat.io rr) descriptionprogZ prefix_charsZformatter_classz-cz --config_ymlz (Config File Required!) example here: https://raw.githubusercontent.com/aws-quickstart/taskcat/master/examples/sample-taskcat-project/ci/taskcat.yml)typehelpz-Pz--boto_profilezAuthenticate using boto profilez-Az--aws_access_keyzAWS Access Keyz-Sz--aws_secret_keyzAWS Secret Keyz-nz --no_cleanup store_truez0Sets cleanup to false (Does not teardown stacks))actionrkz-Nz--no_cleanup_failedzeSets cleaup to false if the stack launch fails (Does not teardown stacks if it experiences a failure)z-pz--public_s3_bucketzSSets public_s3_bucket to True. (Accesses objects via public HTTP, not S3 API calls)z-vz --verbosezEnables verbosityz-tz--tagzdadd tag to cloudformation stack, must be in the format TagKey=TagValue, multiple -t can be specifiedz-sz--stack-prefixtagzYset prefix for cloudformation stack name. only accepts lowercase letters, numbers and '-')rjdefaultrkz-lz--lintzlint the templates and exitz-Vz --versionzPrints Versionz-uz --upload-onlyz!Sync local files with s3 and exitz-bz--lambda-build-onlyzcreate lambda zips and exitz-ez --excluder%z^Exclude directories or files from s3 sync Example: --exclude foo --exclude bar --exclude *.txtz--enable-sig-v2z.Allow sigv2 requests to auto generated bucketsrTz4-c (--config_yml) not passed (Config File Required!)z ^[a-z0-9\-]+$z>--stack-prefix only accepts lowercase letters, numbers and '-'Fz+Cannot use boto profile -P (--boto_profile)z)with --aws_access_key or --aws_secret_keyz:Cannot use -n (--no_cleanup) with -N (--no_cleanup_failed)zTCannot use boto profile -P (--boto_profile)with --aws_access_key or --aws_secret_keyzTCannot use boto profile -P (--boto_profile)with --aws_access_key or --aws_secret_key)&argparseArgumentParserr add_argumentrq AppendTag parse_argsrsysargvwelcomerv print_helprrrrerarcrxerrorr r]AttributeErrorrdrecompilematchr^rDZ no_cleanuprUrVrTrUrVZno_cleanup_failedr\)r,parserrWrrr interfaces           zTaskCat.interfaceFcCsfd}dd}tdkrPdtkr0td}t|kr0d}|s^|sFtdtq^||nttjd ||fS) NFcSsdtdttdtdjtjd|tdjtjtjtjtdjtjtjtjtddS)Nz version %srz*{} A newer version of {} is available ({})rzA{} To upgrade pip version {}[ pip install --upgrade taskcat]{}z@{} To upgrade docker version {}[ docker pull taskcat/taskcat ]{})rvrr rrr'r=)Z newversionrrr_print_upgrade_msgs z2TaskCat.checkforupdate.._print_upgrade_msgrdevz"https://pypi.org/pypi/taskcat/jsonTz version %sz'Using local source (development mode) ) _run_moderrrvrr)ZsilentZ update_neededrcurrent_versionrrrcheckforupdates  zTaskCat.checkforupdaterc Csptjdd}||_tdj|j|dy |jWn6tk rJYn"tk rjtt j dYnXdS)Nstandard)fontz{0}rz(Unable to get version info!!, continuing) pyfigletZFigletrBrvr Z renderTextrr rrr)r,Z prog_namerBrrrrws  zTaskCat.welcome)r8)NN)NN)NN)F)r)Mr4r5r6r-rgrhrirjrkrlrmrnrprrrsrtryrzr{r}r~rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr staticmethodrr rrrr+r.r-rr,rrrQr@rYrZrcrgpropertyrrrwrrrrr7s 3He  +Gl &'4+/n   ?2& $ r7c@seZdZdddZdS)rsNc Csnt|jddkrtd|jd\}}yt|dWn tk rVt|dgYnX|jj||ddS)N=r!z*tags must be in the format TagKey=TagValuer])rValue)rrr getattrrzsetattrr]r%)r,r~rvaluesZ option_stringrJvrrr__call__szAppendTag.__call__)N)r4r5r6rrrrrrssrscCsdS)Nrrrrrmainsr__main__)T)G __future__rrpbase64r$rr!randomr{rur(uuidrrr=loggingZ cfnlint.corerArrZbotocore.vendoredr pkg_resourcesrZtaskcat.reaperrZtaskcat.client_factoryrZtaskcat.colored_consolerZtaskcat.generate_reportsr Ztaskcat.common_utilsr Ztaskcat.cfn_logutilsr Ztaskcat.cfn_resourcesr Ztaskcat.exceptionsr Ztaskcat.s3_syncrrrZtaskcat.template_paramsrrreplacerrr b64decoderrrqZuuid4r getLoggerr;setLevelrrrr(objectr)r7ZActionrsrr4rrrrs                   #