def main(artifact_dir: str, apps: list, bdd_http_proto: str, bdd_url: str, bdd_api_endpoint: str, bdd_version: int, cicd_http_proto: str, cicd_url: str, cicd_api_endpoint: str, cicd_version: int): # use the script variables global bdd_test, bdd_modules, test_names, test_list, test_urls probe_endpoint = build_probe_endpoint( cicd_http_proto, cicd_url, cicd_api_endpoint, cicd_version) bdd_endpoint = build_bdd_endpoint( bdd_http_proto, bdd_url, bdd_api_endpoint, bdd_version) # Query the CICD probe for app in apps: # Removes whitespaces in the beginning and end of the string app = app.strip() response = scan_bdd_test_endpoint(artifact_dir, probe_endpoint, app) if len(response) == 0: continue # It has no test suites, continue the loop for test_endpoint in response: # Get the BDD test endpoints information bdd_test += [{"EspaceName": test_endpoint["BDDTestEndpointsInfo"]["EspaceName"], "WebFlows": test_endpoint["BDDTestEndpointsInfo"]["WebFlows"]}] bdd_modules += len(test_endpoint["BDDTestEndpointsInfo"] ["WebFlows"]) print("{} BDD module(s) found.".format(bdd_modules), flush=True) # Get the tests to run (just for presentation) for bdd in bdd_test: # For each BDD test if "WebFlows" in bdd: # Sanity check to see if there are actual webflows in tests for webflow in bdd["WebFlows"]: # For each webflow if "WebScreens" in webflow: # Sanity check to see if there are actual webscreens in tests test_list += webflow["WebScreens"] print("{} BDD endpoint(s) scanned successfully.".format(len(test_list)), flush=True) # Get the names of the tests to run (just for presentation) for test in test_list: test_names.append(test["Name"]) print("Tests to run:{}".format(test_names), flush=True) # For each test, generate the URL to query the BDD framework, to be used in the test class for bdd in bdd_test: # For each BDD test if "WebFlows" in bdd: # Sanity check to see if there are actual webflows in tests for webflow in bdd["WebFlows"]: # For each webflow if "WebScreens" in webflow: # Sanity check to see if there are actual webscreens in tests for webscreen in webflow["WebScreens"]: # for each webscreen test_endpoint = build_bdd_test_endpoint( bdd_endpoint, bdd["EspaceName"], webscreen["Name"]) test_urls.append( {"TestSuite": bdd["EspaceName"], "Name": webscreen["Name"], "URL": test_endpoint}) # Save the test results in a file for later processing filename = os.path.join(BDD_FRAMEWORK_FOLDER, BDD_FRAMEWORK_TEST_ENDPOINTS_FILE) store_data(artifact_dir, filename, test_urls)
def get_environments(artifact_dir: str, endpoint: str, auth_token: str): # Sends the request response = send_get_request(endpoint, auth_token, ENVIRONMENTS_ENDPOINT, None) status_code = int(response["http_status"]) if status_code == ENVIRONMENTS_SUCCESS_CODE: # Stores the result store_data(artifact_dir, ENVIRONMENTS_FILE, response["response"]) return response["response"] elif status_code == ENVIRONMENTS_NOT_FOUND_CODE: raise EnvironmentNotFoundError( "No environments found. Details {}".format(response["response"])) elif status_code == ENVIRONMENTS_FAILED_CODE: raise ServerError( "Failed to list the environments. Details: {}".format( response["response"])) else: raise NotImplementedError( "There was an error. Response from server: {}".format(response))
def get_environment_app_version(artifact_dir: str, endpoint: str, auth_token: str, extra_data: bool, **kwargs): # Tuple with (AppName, AppKey): app_tuple[0] = AppName; app_tuple[1] = AppKey app_tuple = _get_application_info(artifact_dir, endpoint, auth_token, **kwargs) # Tuple with (EnvName, EnvKey): env_tuple[0] = EnvName; env_tuple[1] = EnvKey env_tuple = _get_environment_info(artifact_dir, endpoint, auth_token, **kwargs) # Builds the query and arguments for the call to the API query = "{}/{}/{}/{}".format(ENVIRONMENTS_ENDPOINT, env_tuple[1], ENVIRONMENT_APPLICATIONS_ENDPOINT, app_tuple[1]) arguments = {"IncludeEnvStatus": extra_data, "IncludeModules": extra_data} # Sends the request response = send_get_request(endpoint, auth_token, query, arguments) status_code = int(response["http_status"]) if status_code == ENVIRONMENT_APP_SUCCESS_CODE: # Stores the result filename = "{}.{}{}".format(env_tuple[0], app_tuple[0], ENVIRONMENT_APPLICATION_FILE) filename = os.path.join(ENVIRONMENT_FOLDER, filename) store_data(artifact_dir, filename, response["response"]) return response["response"] elif status_code == ENVIRONMENT_APP_NOT_STATUS_CODE: raise InvalidParametersError( "Error in the request parameters. Params: {}. Details {}".format( arguments, response["response"])) elif status_code == ENVIRONMENT_APP_NO_PERMISSION_CODE: raise NotEnoughPermissionsError( "You don't have enough permissions to see the application in that environment. Details: {}" .format(response["response"])) elif status_code == ENVIRONMENT_APP_NOT_FOUND: raise AppDoesNotExistError( "The application does not exist in the environment. Details: {}". format(response["response"])) elif status_code == ENVIRONMENT_APP_FAILED_CODE: raise ServerError( "Failed to access the running version of an application. Details: {}" .format(response["response"])) else: raise NotImplementedError( "There was an error. Response from server: {}".format(response))
def generate_regular_deployment(artifact_dir: str, lt_endpoint: str, lt_token: str, src_env_key: str, app_list: list): app_data_list = [ ] # will contain the applications to deploy details from LT deployment_manifest = [ ] # will store the deployment plan, that may be used in later stages of the pipeline # Creates a list with the details for the apps you want to deploy for app_name in app_list: # Removes whitespaces in the beginning and end of the string app_name = app_name.strip() # Get the app running version on the source environment. It will only retrieve tagged applications deployed = get_running_app_version(artifact_dir, lt_endpoint, lt_token, src_env_key, app_name=app_name) # Add it to the app data list app_data_list.append({ 'Name': app_name, 'Key': deployed["ApplicationKey"], 'Version': deployed["Version"], 'VersionKey': deployed["VersionKey"] }) # Add app to manifest, since this is a regular deployment deployment_manifest.append(deployed) # Store the manifest to be used in other stages of the pipeline filename = "{}/{}".format(DEPLOYMENT_FOLDER, DEPLOYMENT_MANIFEST_FILE) store_data(ARTIFACT_FOLDER, filename, deployment_manifest) return app_data_list
def main(artifact_dir: str, lt_http_proto: str, lt_url: str, lt_api_endpoint: str, lt_api_version: int, lt_token: str, source_env: str, dest_env: str, apps: list, dep_manifest: list, dep_note: str): app_data_list = [ ] # will contain the applications to deploy details from LT to_deploy_app_keys = [] # will contain the app keys for the apps tagged # Builds the LifeTime endpoint lt_endpoint = build_lt_endpoint(lt_http_proto, lt_url, lt_api_endpoint, lt_api_version) # Gets the environment key for the source environment src_env_key = get_environment_key(artifact_dir, lt_endpoint, lt_token, source_env) # Gets the environment key for the destination environment dest_env_key = get_environment_key(artifact_dir, lt_endpoint, lt_token, dest_env) # If the manifest file is being used, the app versions MUST come from that file # Or else you might not be deploying the same app versions that were deployed in # previous pipeline steps if dep_manifest: app_data_list = generate_deployment_based_on_manifest( artifact_dir, lt_endpoint, lt_token, src_env_key, source_env, apps, dep_manifest) else: app_data_list = generate_regular_deployment(artifact_dir, lt_endpoint, lt_token, src_env_key, apps) to_deploy_app_keys = check_if_can_deploy(artifact_dir, lt_endpoint, lt_api_version, lt_token, dest_env_key, dest_env, app_data_list) # Check if there are apps to be deployed if len(to_deploy_app_keys) == 0: print( "Deployment skipped because {} environment already has the target application deployed with the same tags." .format(dest_env), flush=True) sys.exit(0) # Write the names and keys of the application versions to be deployed to_deploy_app_names = [] to_deploy_app_info = [] for app in app_data_list: for deploying_apps in to_deploy_app_keys: if lt_api_version == 1: # LT for OS version < 11 if deploying_apps == app["VersionKey"]: to_deploy_app_names.append(app["Name"]) to_deploy_app_info.append(app) elif lt_api_version == 2: # LT for OS v11 if deploying_apps["ApplicationVersionKey"] == app[ "VersionKey"]: to_deploy_app_names.append(app["Name"]) to_deploy_app_info.append(app) else: raise NotImplementedError( "Please make sure the API version is compatible with the module." ) print( "Creating deployment plan from {} to {} including applications: {} ({})." .format(source_env, dest_env, to_deploy_app_names, to_deploy_app_info), flush=True) wait_counter = 0 deployments = get_running_deployment(artifact_dir, lt_endpoint, lt_token, dest_env_key) while len(deployments) > 0: if wait_counter >= QUEUE_TIMEOUT_IN_SECS: print( "Timeout occurred while waiting for LifeTime to be free, to create the new deployment plan.", flush=True) sys.exit(1) sleep(SLEEP_PERIOD_IN_SECS) wait_counter += SLEEP_PERIOD_IN_SECS print("Waiting for LifeTime to be free. Elapsed time: {} seconds...". format(wait_counter), flush=True) deployments = get_running_deployment(artifact_dir, lt_endpoint, lt_token, dest_env_key) # LT is free to deploy # Send the deployment plan and grab the key dep_plan_key = send_deployment(artifact_dir, lt_endpoint, lt_token, lt_api_version, to_deploy_app_keys, dep_note, source_env, dest_env) print("Deployment plan {} created successfully.".format(dep_plan_key), flush=True) # Check if created deployment plan has conflicts dep_details = get_deployment_info(artifact_dir, lt_endpoint, lt_token, dep_plan_key) if len(dep_details["ApplicationConflicts"]) > 0: store_data(artifact_dir, CONFLICTS_FILE, dep_details["ApplicationConflicts"]) print( "Deployment plan {} has conflicts and will be aborted. Check {} artifact for more details." .format(dep_plan_key, CONFLICTS_FILE), flush=True) # Abort previously created deployment plan to target environment delete_deployment(lt_endpoint, lt_token, dep_plan_key) print("Deployment plan {} was deleted successfully.".format( dep_plan_key), flush=True) sys.exit(1) # Check if outdated consumer applications (outside of deployment plan) should be redeployed and start the deployment plan execution if lt_api_version == 1: # LT for OS version < 11 start_deployment(lt_endpoint, lt_token, dep_plan_key) elif lt_api_version == 2: # LT for OS v11 start_deployment(lt_endpoint, lt_token, dep_plan_key, redeploy_outdated=REDEPLOY_OUTDATED_APPS) else: raise NotImplementedError( "Please make sure the API version is compatible with the module.") print("Deployment plan {} started being executed.".format(dep_plan_key), flush=True) # Sleep thread until deployment has finished wait_counter = 0 while wait_counter < DEPLOYMENT_TIMEOUT_IN_SECS: # Check Deployment Plan status. dep_status = get_deployment_status(artifact_dir, lt_endpoint, lt_token, dep_plan_key) if dep_status["DeploymentStatus"] != DEPLOYMENT_RUNNING_STATUS: # Check deployment status is pending approval. Force it to continue (if 2-Step deployment is enabled) if dep_status["DeploymentStatus"] == DEPLOYMENT_WAITING_STATUS: continue_deployment(lt_endpoint, lt_token, dep_plan_key) print("Deployment plan {} resumed execution.".format( dep_plan_key), flush=True) elif dep_status[ "DeploymentStatus"] in DEPLOYMENT_ERROR_STATUS_LIST: print("Deployment plan finished with status {}.".format( dep_status["DeploymentStatus"]), flush=True) store_data(artifact_dir, DEPLOY_ERROR_FILE, dep_status) sys.exit(1) else: # If it reaches here, it means the deployment was successful print("Deployment plan finished with status {}.".format( dep_status["DeploymentStatus"]), flush=True) # Exit the script to continue with the pipeline sys.exit(0) # Deployment status is still running. Go back to sleep. sleep(SLEEP_PERIOD_IN_SECS) wait_counter += SLEEP_PERIOD_IN_SECS print("{} secs have passed since the deployment started...".format( wait_counter), flush=True) # Deployment timeout reached. Exit script with error print( "Timeout occurred while deployment plan is still in {} status.".format( DEPLOYMENT_RUNNING_STATUS), flush=True) sys.exit(1)