def search_and_install_packs_and_their_dependencies_private( test_pack_path: str, pack_ids: list, client: demisto_client, prints_manager: ParallelPrintsManager, thread_index: int = 0): """ Searches for the packs from the specified list, searches their dependencies, and then installs them. Args: test_pack_path (str): Path of where the test packs are located. pack_ids (list): A list of the pack ids to search and install. client (demisto_client): The client to connect to. prints_manager (ParallelPrintsManager): A prints manager object. thread_index (int): the thread index. Returns (list, bool): A list of the installed packs' ids, or an empty list if is_nightly == True. A flag that indicates if the operation succeeded or not. """ host = client.api_client.configuration.host msg = f'Starting to search and install packs in server: {host}' prints_manager.add_print_job(msg, print_color, thread_index, LOG_COLORS.GREEN) prints_manager.execute_thread_prints(thread_index) install_packs_private(client, host, prints_manager, thread_index, pack_ids, test_pack_path) return SUCCESS_FLAG
def install_packs_from_artifacts(client: demisto_client, host: str, prints_manager: ParallelPrintsManager, thread_index: int, test_pack_path: str, pack_ids_to_install: List): """ Installs all the packs located in the artifacts folder of the BitHub actions build. Please note: The server always returns a 200 status even if the pack was not installed. :param client: Demisto-py client to connect to the server. :param host: FQDN of the server. :param prints_manager: ParallelPrintsManager - Will be deprecated. :param thread_index: Integer indicating which thread the test is running on. :param test_pack_path: Path the the test pack directory. :param pack_ids_to_install: List of pack IDs to install. :return: None. Call to server waits until a successful response. """ print(f"Test pack path is: {test_pack_path}") print(f"Pack IDs to install are: {pack_ids_to_install}") local_packs = glob.glob(f"{test_pack_path}/*.zip") for local_pack in local_packs: if any(pack_id in local_pack for pack_id in pack_ids_to_install): packs_install_msg = f'Installing the following pack: {local_pack}' prints_manager.add_print_job(packs_install_msg, print_color, thread_index, LOG_COLORS.GREEN, include_timestamp=True) upload_zipped_packs(client=client, host=host, prints_manager=prints_manager, thread_index=thread_index, pack_path=local_pack)
def install_packs_private(build: Build, prints_manager: ParallelPrintsManager, pack_ids: list = None) -> bool: """ Wrapper for the search and install packs function. :param build: Build object containing the build settings. :param prints_manager: PrintsManager object used for reporting status. Will be deprecated. :param pack_ids: Optional, list of packs to install. List contains pack id and version requested. :return: Boolean indicating if the installation was successful. """ pack_ids = pack_ids if pack_ids else build.pack_ids_to_install installed_content_packs_successfully = True for server in build.servers: try: flag = search_and_install_packs_and_their_dependencies_private( build.test_pack_path, pack_ids, server.client) if not flag: raise Exception('Failed to search and install packs.') except Exception as exc: prints_manager.add_print_job(str(exc), print_error, 0) prints_manager.execute_thread_prints(0) installed_content_packs_successfully = False return installed_content_packs_successfully
def update_round_set_and_sleep_if_round_completed( executed_in_current_round: set, prints_manager: ParallelPrintsManager, t: dict, thread_index: int) -> set: """ Checks if the string representation of the current test configuration is already in the executed_in_current_round set. If it is- it means we have already executed this test and the we have reached a round and there are tests that were not able to be locked by this execution.. In that case we want to start a new round monitoring by emptying the 'executed_in_current_round' set and sleep in order to let the tests be unlocked Args: executed_in_current_round: A set containing the string representation of all tests configuration as they appear in conf.json file that were already executed in the current round prints_manager: ParallelPrintsManager object t: test configuration as it appears in conf.json file thread_index: Currently executing thread Returns: A new executed_in_current_round set which contains only the current tests configuration if a round was completed else it just adds the new test to the set. """ if str(t) in executed_in_current_round: prints_manager.add_print_job( 'all tests in the queue were executed, sleeping for 30 seconds to let locked tests get unlocked.', print, thread_index) executed_in_current_round = set() time.sleep(30) executed_in_current_round.add(str(t)) return executed_in_current_round
def test_instances(secret_conf_path, server, username, password): integrations = get_integrations(secret_conf_path) instance_ids = [] failed_integrations = [] integrations_counter = 0 prints_manager = ParallelPrintsManager(1) content_installation_client = demisto_client.configure(base_url=server, username=username, password=password, verify_ssl=False) install_new_content(content_installation_client, server) for integration in integrations: c = demisto_client.configure(base_url=server, username=username, password=password, verify_ssl=False) integrations_counter += 1 integration_name = integration.get('name') integration_instance_name = integration.get('instance_name', '') integration_params = integration.get('params') devops_comments = integration.get('devops_comments') product_description = integration.get('product_description', '') is_byoi = integration.get('byoi', True) has_integration = integration.get('has_integration', True) validate_test = integration.get('validate_test', True) if has_integration: instance_id, failure_message, _ = __create_integration_instance( c, integration_name, integration_instance_name, integration_params, is_byoi, prints_manager, validate_test=validate_test) if failure_message == 'No configuration': print_warning( "Warning: skipping {} as it exists in content-test-conf conf.json but not " "in content repo".format(integration_name)) continue if not instance_id: print_error( 'Failed to create instance of {} with message: {}'.format( integration_name, failure_message)) failed_integrations.append( "{} {} - devops comments: {}".format( integration_name, product_description, devops_comments)) else: instance_ids.append(instance_id) print('Create integration %s succeed' % (integration_name, )) __delete_integrations_instances(c, instance_ids, prints_manager) prints_manager.execute_thread_prints(0) return failed_integrations, integrations_counter
def search_and_install_packs_and_their_dependencies_private( test_pack_path: str, pack_ids: list, client: demisto_client, prints_manager: ParallelPrintsManager, thread_index: int = 0): """ Searches for the packs from the specified list, searches their dependencies, and then installs them. Args: test_pack_path (str): Path of where the test packs are located. pack_ids (list): A list of the pack ids to search and install. client (demisto_client): The client to connect to. prints_manager (ParallelPrintsManager): A prints manager object. thread_index (int): the thread index. Returns (list, bool): A list of the installed packs' ids, or an empty list if is_nightly == True. A flag that indicates if the operation succeeded or not. """ host = client.api_client.configuration.host msg = f'Starting to search and install packs in server: {host}' prints_manager.add_print_job(msg, print_color, thread_index, LOG_COLORS.GREEN) prints_manager.execute_thread_prints(thread_index) packs_to_install = [ ] # we save all the packs we want to install, to avoid duplications installation_request_body = [ ] # the packs to install, in the request format threads_list = [] lock = Lock() for pack_id in pack_ids: thread = Thread(target=search_pack_and_its_dependencies, kwargs={ 'client': client, 'prints_manager': prints_manager, 'pack_id': pack_id, 'packs_to_install': packs_to_install, 'installation_request_body': installation_request_body, 'thread_index': thread_index, 'lock': lock }) threads_list.append(thread) run_threads_list(threads_list) install_packs_private(client, host, prints_manager, thread_index, pack_ids, test_pack_path) return packs_to_install, SUCCESS_FLAG
def manage_tests(tests_settings: SettingsTester): """ This function manages the execution of Demisto's tests. Args: tests_settings (SettingsTester): An object containing all the relevant data regarding how the tests should be ran. """ tests_settings.serverNumericVersion = get_server_numeric_version(tests_settings.serverVersion, tests_settings.is_local_run) instances_ips = get_instances_ips_and_names(tests_settings) number_of_instances = len(instances_ips) prints_manager = ParallelPrintsManager(number_of_instances) tests_data_keeper = DataKeeperTester() for ami_instance_name, ami_instance_ip in instances_ips: if ami_instance_name == tests_settings.serverVersion: print_color("Starting private testing for {}".format(ami_instance_name), LOG_COLORS.GREEN) print("Starts tests with server url - https://{}".format(ami_instance_ip)) all_tests = get_all_tests(tests_settings) execute_testing(tests_settings, ami_instance_ip, all_tests, tests_data_keeper, prints_manager, thread_index=0) sleep(8) print_test_summary(tests_data_keeper, tests_settings.isAMI) create_result_files(tests_data_keeper) if tests_data_keeper.failed_playbooks: tests_failed_msg = "Some tests have failed. Not destroying instances." print(tests_failed_msg) sys.exit(1)
def test_install_packs_private(mocker): """ Scenario: Given a pack ID to install, the test will simulate opening the content_packs_to_install file and will first install the Demisto test license, then install the pack from the artifacts directory. Important to note here, that the server does not return any status code to indicate that the upload was successful. As long as the request returns a 200, we assume the installation was successful. This should be changed at some point however. Given: The test pack ID "TEST" When: Installing the pack from the artifacts directory Then: Collect the pack ID from the packs to install file, update the license, and upload the pack. """ prints_manager = ParallelPrintsManager(len(BuildMock().servers)) mocker.patch('Tests.Marketplace.search_and_install_packs.open', return_value=StringIO('HelloWorld\nTEST')) mocker.patch('Tests.Marketplace.search_and_install_packs.search_pack_and_its_dependencies') def mocked_generic_request_func(self, path: str, method, body=None, accept=None, _request_timeout=None): if path == '/contentpacks/marketplace/install': return 'MOCK_PACKS_INSTALLATION_RESULT', 200, None return None, None, None mocker.patch.object(demisto_client, 'generic_request_func', side_effect=mocked_generic_request_func) mocker.patch.object(glob, 'glob', return_value=['content/artifacts/packs/TEST.zip']) mock_build = BuildMock() mock_build.test_pack_path = 'content/artifacts/packs' mock_build.pack_ids_to_install = ['TestPack'] test_results = install_packs_private(build=mock_build, prints_manager=prints_manager, pack_ids=['TEST']) assert test_results is True
def test_search_and_install_packs_and_their_dependencies(mocker): """ Given - Valid and invalid integrations paths. When - Running integrations configuration tests. Then - Ensure packs & their dependencies' search requests are valid. - Ensure packs & their dependencies' installation requests are valid. """ good_pack_ids = ['HelloWorld', 'AzureSentinel'] bad_pack_ids = ['malformed_pack_id'] client = MockClient() mocker.patch.object(demisto_client, 'generic_request_func', side_effect=mocked_generic_request_func) mocker.patch.object(script, 'get_pack_display_name', side_effect=mocked_get_pack_display_name) prints_manager = ParallelPrintsManager(1) installed_packs, success = script.search_and_install_packs_and_their_dependencies( good_pack_ids, client, prints_manager, is_private=False) assert 'HelloWorld' in installed_packs assert 'AzureSentinel' in installed_packs assert 'TestPack' in installed_packs assert success is True installed_packs, _ = script.search_and_install_packs_and_their_dependencies( bad_pack_ids, client, prints_manager, is_private=False) assert bad_pack_ids[0] not in installed_packs
def main(): install_logging('Configure and Install Packs.log') options = options_handler() # Get the host by the ami env hosts, _ = Build.get_servers(ami_env=options.ami_env) logging.info('Retrieving the credentials for Cortex XSOAR server') secret_conf_file = get_json_file(path=options.secret) username: str = secret_conf_file.get('username') password: str = secret_conf_file.get('userPassword') # Configure the Servers for host in hosts: server = Server(host=host, user_name=username, password=password) logging.info(f'Adding Marketplace configuration to {host}') error_msg: str = 'Failed to set marketplace configuration.' server.add_server_configuration(config_dict=MARKET_PLACE_CONFIGURATION, error_msg=error_msg) set_marketplace_url(servers=[server], branch_name=options.branch, ci_build_number=options.build_number) # Acquire the server's host and install all content packs (one threaded execution) logging.info(f'Starting to install all content packs in {host}') server_host: str = server.client.api_client.configuration.host install_all_content_packs(client=server.client, host=server_host, prints_manager=ParallelPrintsManager(1)) logging.success(f'Finished installing all content packs in {host}')
def test_search_and_install_packs_and_their_dependencies_with_error(mocker): """ Given - Error when searching for a pack When - Running integrations configuration tests. Then - Ensure a flag is raised """ good_pack_ids = ['HelloWorld'] client = MockClient() mocker.patch.object(script, 'install_packs') mocker.patch.object(demisto_client, 'generic_request_func', return_value=('', 500, None)) mocker.patch.object(script, 'get_pack_display_name', side_effect=mocked_get_pack_display_name) prints_manager = ParallelPrintsManager(1) installed_packs, success = script.search_and_install_packs_and_their_dependencies( good_pack_ids, client, prints_manager, is_private=False) assert success is False
def test_search_and_install_packs_and_their_dependencies(mocker): """ Given - Valid and invalid integrations paths. When - Running integrations configuration tests. Then - Ensure packs & their depenencies' search requests are valid. - Ensure packs & their depenencies' installation requests are valid. """ good_integrations_files = [ 'Packs/HelloWorld/Integrations/HelloWorld/HelloWorld.yml', 'Packs/AzureSentinel/Integrations/AzureSentinel/AzureSentinel.yml' ] bad_integrations_files = ['malformed_integration_file'] client = MockClient() mocker.patch.object(demisto_client, 'generic_request_func', side_effect=mocked_generic_request_func) prints_manager = ParallelPrintsManager(1) installed_packs = search_and_install_packs_and_their_dependencies( good_integrations_files, client, prints_manager) assert 'HelloWorld' in installed_packs assert 'AzureSentinel' in installed_packs assert 'TestPack' in installed_packs assert 'Base' in installed_packs assert len(installed_packs) == 4 installed_packs = search_and_install_packs_and_their_dependencies( bad_integrations_files, client, prints_manager) assert len(installed_packs) == 0
def test_search_pack_with_failure(mocker): """ Given - Error when searching for pack - Response with missing data When - Searching the pack in the Demsito instance for installation. Then - Ensure error is raised. """ client = MockClient() prints_manager = ParallelPrintsManager(1) lock = MockLock() # Error when searching for pack mocker.patch.object(demisto_client, 'generic_request_func', return_value=('', 500, None)) script.search_pack(client, prints_manager, "New Hello World", 'HelloWorld', 0, lock) assert not script.SUCCESS_FLAG # Response with missing data mocker.patch.object(demisto_client, 'generic_request_func', return_value=('{"id": "HelloWorld"}', 200, None)) script.search_pack(client, prints_manager, "New Hello World", 'HelloWorld', 0, lock) assert not script.SUCCESS_FLAG
def test_print_investigation_error(command, output, mocker): """ Given - A failed playbook task command line. When - Extracting the task error reason from the server Then - Ensure message sent to print manager contains `password=******` instead of `password="******"` - Ensure message sent to print manager contains `password=******` instead of `Password="******"` - Ensure message sent to print manager contains "pass word="123123!"" """ prints_manager = ParallelPrintsManager(1) body = { 'entries': [{ 'type': 4, 'parentContent': command, 'taskId': '12', 'contents': '2' }] } mocker.patch.object(demisto_client, "generic_request_func", return_value=[str(body), '200']) client = demisto_client __print_investigation_error(client, '', '', prints_manager) prints_to_execute = prints_manager.threads_print_jobs[0] assert prints_to_execute[2].message_to_print == output
def run_test(tests_settings: SettingsTester, demisto_user: str, demisto_pass: str, failed_playbooks: list, integrations: list, playbook_id: str, succeed_playbooks: list, test_message: str, test_options: dict, slack: str, circle_ci: str, build_number: str, server_url: str, build_name: str, prints_manager: ParallelPrintsManager, thread_index: int = 0) -> None: """ Wrapper for the run_test_logic function. Helps by indicating when the test is starting and ending. :param tests_settings: SettingsTester object which contains the test variables :param demisto_user: Username of the demisto user running the tests. :param demisto_pass: Password of the demisto user running the tests. :param failed_playbooks: List of failed playbooks, additional failed playbooks will be added if they failed. :param integrations: List of integrations being tested. :param playbook_id: ID of the test playbook being tested. :param succeed_playbooks: List of playbooks which have passed tests. :param test_message: Name of the playbook/integration being tested. This is reported back in the build and used to print in the console the test being ran. :param test_options: Options being passed to the test. PID, Docker Threshold, Timeout, etc. :param slack: Slack client used for notifications. :param circle_ci: CircleCI token. Used to get name of dev who triggered the build. :param build_number: The build number of the CI run. Used in slack message. :param server_url: The FQDN of the server tests are being ran on. :param build_name: Name of the build. (Nightly, etc.) :param prints_manager: PrintsManager object used in reporting. Will be deprecated. :param thread_index: Integer indicating what thread the test is running on. :return: No object is returned. """ start_message = f'------ Test {test_message} start ------' client = demisto_client.configure(base_url=server_url, username=demisto_user, password=demisto_pass, verify_ssl=False) prints_manager.add_print_job(start_message + ' (Private Build Test)', print, thread_index, include_timestamp=True) run_test_logic(tests_settings, client, failed_playbooks, integrations, playbook_id, succeed_playbooks, test_message, test_options, slack, circle_ci, build_number, server_url, demisto_user, demisto_pass, build_name, prints_manager, thread_index=thread_index) prints_manager.add_print_job('------ Test %s end ------\n' % (test_message,), print, thread_index, include_timestamp=True) return
def install_private_testing_pack(build: Build, prints_manager: ParallelPrintsManager, test_pack_zip_path: str): """ Creates and installs the test pack used in the private build. This pack contains the test playbooks and test scripts that will be used for the tests. :param build: Build object containing the build settings. :param prints_manager: PrintsManager object used for reporting status. Will be deprecated. :param test_pack_zip_path: Path to test_pack zip. :return: No object is returned. nightly_install_packs will wait for the process to finish. """ threads_print_manager = ParallelPrintsManager(len(build.servers)) nightly_install_packs(build, threads_print_manager, install_method=upload_zipped_packs, pack_path=test_pack_zip_path) prints_manager.add_print_job('Sleeping for 45 seconds...', print_warning, 0, include_timestamp=True) prints_manager.execute_thread_prints(0)
def main(): build = Build(options_handler()) prints_manager = ParallelPrintsManager(1) configure_servers_and_restart(build, prints_manager) # Get a list of the test we need to run. tests_for_iteration = get_tests(build.server_numeric_version, prints_manager, build.tests) # Installing the packs. installed_content_packs_successfully = install_packs_private( build, prints_manager) # Get a list of the integrations that have changed. new_integrations, modified_integrations = get_changed_integrations( build, prints_manager) # Configuring the instances which are used in testing. all_module_instances, brand_new_integrations = \ configure_server_instances(build, tests_for_iteration, new_integrations, modified_integrations, prints_manager) # Running the instance tests (pushing the test button) successful_tests_pre, failed_tests_pre = instance_testing( build, all_module_instances, prints_manager, pre_update=True) # Adding the new integrations to the instance test list and testing them. all_module_instances.extend(brand_new_integrations) successful_tests_post, failed_tests_post = instance_testing( build, all_module_instances, prints_manager, pre_update=False) # Done running tests so we are disabling the instances. disable_instances(build, all_module_instances, prints_manager) # Gather tests to add to test pack test_playbooks_from_id_set = build.id_set.get('TestPlaybooks', []) tests_to_add_to_test_pack = find_needed_test_playbook_paths( test_playbooks=test_playbooks_from_id_set, tests_to_run=build.tests_to_run, path_to_content=build.content_root) # Write the test pack private_content_test_zip = write_test_pack_zip( zip_destination_dir=build.test_pack_path, tests_file_paths=tests_to_add_to_test_pack, path_to_content=build.content_root) # Create and install private test pack install_private_testing_pack(build, prints_manager, private_content_test_zip) success = report_tests_status(failed_tests_pre, failed_tests_post, successful_tests_pre, successful_tests_post, new_integrations, prints_manager) sleep(30) if not success or not installed_content_packs_successfully: sys.exit(2)
def test_search_pack_with_id(mocker): """ Given - Pack with a new name (different from its ID) When - Searching the pack in the Demsito instance. Then - Ensure the pack is found using its ID """ client = MockClient() prints_manager = ParallelPrintsManager(1) mocker.patch.object(demisto_client, 'generic_request_func', side_effect=mocked_generic_request_func) expected_response = { 'id': 'HelloWorld', 'version': '1.1.10' } assert expected_response == script.search_pack(client, prints_manager, "New Hello World", 'HelloWorld', 0, None)
def test_create_install_private_testing_pack(mocker): """ Scenario: Creating and installing a pack for testing. Pack will contain no items as it is mocked in this test. Empty pack will be created and uploaded to mock server. Server returns a 200 status code. Given: A mocked test pack When: Installing a pack to the server Then: Return the success flag set to true indicating the request to install the pack was successful """ prints_manager = ParallelPrintsManager(len(BuildMock().servers)) def mocked_generic_request_func(self, path: str, method, body=None, accept=None, _request_timeout=None): if path == '/contentpacks/marketplace/install': return 'MOCK_PACKS_INSTALLATION_RESULT', 200, None return None, None, None mocker.patch.object(demisto_client, 'generic_request_func', side_effect=mocked_generic_request_func) mock_build = BuildMock() install_private_testing_pack(mock_build, prints_manager, 'testing/path/to/test_pack.zip') assert script.SUCCESS_FLAG
def get_pack_dependencies(client: demisto_client, prints_manager: ParallelPrintsManager, pack_data: dict, thread_index: int, lock: Lock): """ Get the pack's required dependencies. Args: client (demisto_client): The configured client to use. prints_manager (ParallelPrintsManager): A prints manager object. pack_data (dict): Contains the pack ID and version. thread_index (int): the thread index. lock (Lock): A lock object. Returns: (list) The pack's dependencies. """ pack_id = pack_data['id'] try: response_data, status_code, _ = demisto_client.generic_request_func( client, path='/contentpacks/marketplace/search/dependencies', method='POST', body=[pack_data], accept='application/json', _request_timeout=None) if 200 <= status_code < 300: dependencies_data = [] dependants_ids = [pack_id] reseponse_data = ast.literal_eval(response_data).get( 'dependencies', []) create_dependencies_data_structure(reseponse_data, dependants_ids, dependencies_data, dependants_ids) dependencies_str = ', '.join( [dep['id'] for dep in dependencies_data]) if dependencies_data: message = 'Found the following dependencies for pack {}:\n{}\n'.format( pack_id, dependencies_str) prints_manager.add_print_job(message, print_color, thread_index, LOG_COLORS.GREEN) prints_manager.execute_thread_prints(thread_index) return dependencies_data if status_code == 400: err_msg = f"Unable to find dependencies for {pack_id}." prints_manager.add_print_job(err_msg, print_color, thread_index, LOG_COLORS.RED) prints_manager.execute_thread_prints(thread_index) return [] else: result_object = ast.literal_eval(response_data) msg = result_object.get('message', '') err_msg = 'Failed to get pack {} dependencies - with status code {}\n{}\n'.format( pack_id, status_code, msg) raise Exception(err_msg) except Exception as e: err_msg = 'The request to get pack {} dependencies has failed. Reason:\n{}\n'.format( pack_id, str(e)) prints_manager.add_print_job(err_msg, print_color, thread_index, LOG_COLORS.RED) prints_manager.execute_thread_prints(thread_index) lock.acquire() global SUCCESS_FLAG SUCCESS_FLAG = False lock.release()
def upload_zipped_packs(client: demisto_client, host: str, prints_manager: ParallelPrintsManager, thread_index: int, pack_path: str): """ Install packs from zip file. Args: client (demisto_client): The configured client to use. host (str): The server URL. prints_manager (ParallelPrintsManager): Print manager object. thread_index (int): the index (for prints_manager). pack_path (str): path to pack zip. """ header_params = {'Content-Type': 'multipart/form-data'} file_path = os.path.abspath(pack_path) files = {'file': file_path} message = 'Making "POST" request to server {} - to install all packs from file {}'.format( host, pack_path) prints_manager.add_print_job(message, print_color, thread_index, LOG_COLORS.GREEN) prints_manager.execute_thread_prints(thread_index) # make the pack installation request try: response_data, status_code, _ = client.api_client.call_api( resource_path='/contentpacks/installed/upload', method='POST', header_params=header_params, files=files) if 200 <= status_code < 300: message = 'All packs from {} were successfully installed!\n'.format( pack_path) prints_manager.add_print_job(message, print_color, thread_index, LOG_COLORS.GREEN) prints_manager.execute_thread_prints(thread_index) else: result_object = ast.literal_eval(response_data) message = result_object.get('message', '') err_msg = 'Failed to install packs - with status code {}\n{}\n'.format( status_code, message) raise Exception(err_msg) except Exception as e: if e.__class__ == ApiException: err_msg = 'The request to install packs has failed. Reason:\n{}\n'.format( str(e.body)) else: err_msg = 'The request to install packs has failed. Reason:\n{}\n'.format( str(e)) prints_manager.add_print_job(err_msg, print_color, thread_index, LOG_COLORS.GREEN) prints_manager.execute_thread_prints(thread_index) sys.exit(1)
def install_new_content(client, server): prints_manager = ParallelPrintsManager(1) update_content_on_demisto_instance(client, server, prints_manager, 0) prints_manager.execute_thread_prints(0)
def execute_testing(tests_settings: SettingsTester, server_ip: str, all_tests: set, tests_data_keeper: DataKeeperTester, prints_manager: ParallelPrintsManager, thread_index: int = 0): """ Main function used to handle the testing process. Starts by turning off telemetry and disabling any left over tests. Afterwards it will create a test queue object which then is used to run the specific test scenario. :param tests_settings: SettingsTester object which contains the test variables :param server_ip: IP address of the server. Will be formatted before use. :param all_tests: All tests currently in the test conf. :param tests_data_keeper: Object containing all the test results. Used by report tests function. :param prints_manager: PrintsManager object used in reporting. Will be deprecated. :param thread_index: Integer indicating what thread the test is running on. :return: No object is returned, just updates the tests_data_keep object. """ server = SERVER_URL.format(server_ip) server_numeric_version = tests_settings.serverNumericVersion start_message = "Executing tests with the server {} - and the server ip {}".format( server, server_ip) prints_manager.add_print_job(start_message, print, thread_index) slack = tests_settings.slack circle_ci = tests_settings.circleci build_number = tests_settings.buildNumber build_name = tests_settings.buildName conf, secret_conf = load_conf_files(tests_settings.conf_path, tests_settings.secret_conf_path) demisto_api_key = tests_settings.api_key demisto_user = secret_conf['username'] demisto_pass = secret_conf['userPassword'] default_test_timeout = conf.get('testTimeout', 30) tests = conf['tests'] skipped_tests_conf = conf['skipped_tests'] nightly_integrations = conf['nightly_integrations'] skipped_integrations_conf = conf['skipped_integrations'] unmockable_integrations = conf['unmockable_integrations'] secret_params = secret_conf['integrations'] if secret_conf else [] filtered_tests = extract_filtered_tests() if not tests or len(tests) == 0: prints_manager.add_print_job('no integrations are configured for test', print, thread_index) prints_manager.execute_thread_prints(thread_index) return xsoar_client = demisto_client.configure(base_url=server, username=demisto_user, password=demisto_pass, verify_ssl=False) # turn off telemetry turn_off_telemetry(xsoar_client) failed_playbooks = [] succeed_playbooks = [] skipped_tests = set([]) skipped_integration = set([]) playbook_skipped_integration = set([]) disable_all_integrations(xsoar_client, prints_manager, thread_index=thread_index) prints_manager.execute_thread_prints(thread_index) # Private builds do not use mocking. Here we copy the mocked test list to the unmockable list. private_tests = get_test_records_of_given_test_names( tests_settings, all_tests) try: # first run the mock tests to avoid mockless side effects in container prints_manager.add_print_job("\nRunning private tests", print, thread_index) executed_in_current_round, private_tests_queue = initialize_queue_and_executed_tests_set( private_tests) while not private_tests_queue.empty(): t = private_tests_queue.get() executed_in_current_round = update_round_set_and_sleep_if_round_completed( executed_in_current_round, prints_manager, t, thread_index) run_private_test_scenario(tests_settings, t, default_test_timeout, skipped_tests_conf, nightly_integrations, skipped_integrations_conf, skipped_integration, filtered_tests, skipped_tests, secret_params, failed_playbooks, playbook_skipped_integration, succeed_playbooks, slack, circle_ci, build_number, server, build_name, server_numeric_version, demisto_user, demisto_pass, demisto_api_key, prints_manager, thread_index=thread_index) prints_manager.execute_thread_prints(thread_index) except Exception as exc: if exc.__class__ == ApiException: error_message = exc.body else: error_message = f'~~ Thread {thread_index + 1} failed ~~\n{str(exc)}\n{traceback.format_exc()}' prints_manager.add_print_job(error_message, print_error, thread_index) prints_manager.execute_thread_prints(thread_index) failed_playbooks.append(f'~~ Thread {thread_index + 1} failed ~~') raise finally: tests_data_keeper.add_tests_data(succeed_playbooks, failed_playbooks, skipped_tests, skipped_integration, unmockable_integrations)
def main(): options = options_handler() username = options.user password = options.password ami_env = options.ami_env git_sha1 = options.git_sha1 conf_path = options.conf secret_conf_path = options.secret branch_name = options.branch ci_build_number = options.build_number servers = determine_servers_urls(ami_env) server_numeric_version = get_server_numeric_version(ami_env) prints_manager = ParallelPrintsManager(1) conf, secret_conf = load_conf_files(conf_path, secret_conf_path) secret_params = secret_conf.get('integrations', []) if secret_conf else [] username = secret_conf.get('username') if not username else username password = secret_conf.get('userPassword') if not password else password if LooseVersion(server_numeric_version) >= LooseVersion('6.0.0'): for server in servers: client = demisto_client.configure(base_url=server, username=username, password=password, verify_ssl=False) set_marketplace_gcp_bucket_for_build(client, prints_manager, branch_name, ci_build_number) print('Restarting servers to apply GCS server config ...') ssh_string = 'ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null {}@{} ' \ '"sudo systemctl restart demisto"' try: subprocess.check_output( ssh_string.format('ec2-user', server.replace('https://', '')), shell=True) except subprocess.CalledProcessError as exc: print(exc.output) print('Done restarting servers.') tests = conf['tests'] skipped_integrations_conf = conf['skipped_integrations'] all_module_instances = [] filtered_tests, filter_configured, run_all_tests = extract_filtered_tests(is_nightly=options.is_nightly) tests_for_iteration = tests if run_all_tests: # skip test button testing skipped_instance_test_message = 'Not running instance tests when {} is turned on'.format(RUN_ALL_TESTS_FORMAT) prints_manager.add_print_job(skipped_instance_test_message, print_warning, 0) tests_for_iteration = [] elif filter_configured and filtered_tests: tests_for_iteration = [test for test in tests if test.get('playbookID', '') in filtered_tests] tests_for_iteration = filter_tests_with_incompatible_version(tests_for_iteration, server_numeric_version, prints_manager) prints_manager.execute_thread_prints(0) # get a list of brand new integrations that way we filter them out to only configure instances # after updating content new_integrations_files, modified_integrations_files = get_new_and_modified_integration_files(git_sha1) new_integrations_names, modified_integrations_names = [], [] installed_content_packs_successfully = True if LooseVersion(server_numeric_version) >= LooseVersion('6.0.0'): # sleep for one minute before starting to search and install packs to ensure bucket is ready prints_manager.add_print_job('Sleeping for 1 minute...', print_warning, 0) prints_manager.execute_thread_prints(0) sleep(60) pack_ids = get_pack_ids_to_install() # install content packs in every server for server_url in servers: try: client = demisto_client.configure(base_url=server_url, username=username, password=password, verify_ssl=False) search_and_install_packs_and_their_dependencies(pack_ids, client, prints_manager, options.is_nightly) except Exception as exc: prints_manager.add_print_job(str(exc), print_error, 0) prints_manager.execute_thread_prints(0) installed_content_packs_successfully = False if new_integrations_files: new_integrations_names = get_integration_names_from_files(new_integrations_files) new_integrations_names_message = \ 'New Integrations Since Last Release:\n{}\n'.format('\n'.join(new_integrations_names)) prints_manager.add_print_job(new_integrations_names_message, print_warning, 0) if modified_integrations_files: modified_integrations_names = get_integration_names_from_files(modified_integrations_files) modified_integrations_names_message = \ 'Updated Integrations Since Last Release:\n{}\n'.format('\n'.join(modified_integrations_names)) prints_manager.add_print_job(modified_integrations_names_message, print_warning, 0) prints_manager.execute_thread_prints(0) # Each test is a dictionary from Tests/conf.json which may contain the following fields # "playbookID", "integrations", "instance_names", "timeout", "nightly", "fromversion", "toversion" # Note that only the "playbookID" field is required with all of the others being optional. # Most tests have an "integrations" field listing the integration used for that playbook # and sometimes an "instance_names" field which is used when there are multiple instances # of an integration that we want to configure with different configuration values. Look at # [conf.json](../conf.json) for examples brand_new_integrations = [] for test in tests_for_iteration: testing_client = demisto_client.configure(base_url=servers[0], username=username, password=password, verify_ssl=False) integrations = get_integrations_for_test(test, skipped_integrations_conf) instance_names_conf = test.get('instance_names', []) if not isinstance(instance_names_conf, list): instance_names_conf = [instance_names_conf] integrations_names = [i.get('name') for i in integrations] prints_manager.add_print_job('All Integrations for test "{}":'.format(test.get('playbookID')), print_warning, 0) prints_manager.add_print_job(integrations_names, print_warning, 0) new_integrations, modified_integrations, unchanged_integrations, integration_to_status = group_integrations( integrations, skipped_integrations_conf, new_integrations_names, modified_integrations_names ) integrations_msg = '\n'.join(['"{}" - {}'.format(key, val) for key, val in integration_to_status.items()]) prints_manager.add_print_job('{}\n'.format(integrations_msg), print_warning, 0) integrations_to_configure = modified_integrations[:] integrations_to_configure.extend(unchanged_integrations) # set params for new integrations and [modified + unchanged] integrations, then add the new ones # to brand_new_integrations list for later use placeholders_map = {'%%SERVER_HOST%%': servers[0]} new_ints_params_set = set_integration_params(new_integrations, secret_params, instance_names_conf, placeholders_map) ints_to_configure_params_set = set_integration_params(integrations_to_configure, secret_params, instance_names_conf, placeholders_map) if not new_ints_params_set: prints_manager.add_print_job( 'failed setting parameters for integrations "{}"'.format('\n'.join(new_integrations)), print_error, 0) if not ints_to_configure_params_set: prints_manager.add_print_job( 'failed setting parameters for integrations "{}"'.format('\n'.join(integrations_to_configure)), print_error, 0) if not (new_ints_params_set and ints_to_configure_params_set): continue prints_manager.execute_thread_prints(0) brand_new_integrations.extend(new_integrations) module_instances = [] for integration in integrations_to_configure: placeholders_map = {'%%SERVER_HOST%%': servers[0]} module_instance = configure_integration_instance(integration, testing_client, prints_manager, placeholders_map) if module_instance: module_instances.append(module_instance) all_module_instances.extend(module_instances) preupdate_fails = set() postupdate_fails = set() preupdate_success = set() postupdate_success = set() # Test all module instances (of modified + unchanged integrations) pre-updating content if all_module_instances: # only print start message if there are instances to configure prints_manager.add_print_job('Start of Instance Testing ("Test" button) prior to Content Update:', print_warning, 0) else: prints_manager.add_print_job('No integrations to configure for the chosen tests. (Pre-update)', print_warning, 0) prints_manager.execute_thread_prints(0) for instance in all_module_instances: testing_client = demisto_client.configure(base_url=servers[0], username=username, password=password, verify_ssl=False) integration_of_instance = instance.get('brand', '') instance_name = instance.get('name', '') msg = 'Testing ("Test" button) for instance "{}" of integration "{}".'.format(instance_name, integration_of_instance) prints_manager.add_print_job(msg, print_color, 0, LOG_COLORS.GREEN) prints_manager.execute_thread_prints(0) # If there is a failure, __test_integration_instance will print it success, _ = __test_integration_instance(testing_client, instance, prints_manager) prints_manager.execute_thread_prints(0) if not success: preupdate_fails.add((instance_name, integration_of_instance)) else: preupdate_success.add((instance_name, integration_of_instance)) if LooseVersion(server_numeric_version) < LooseVersion('6.0.0'): threads_list = [] threads_prints_manager = ParallelPrintsManager(len(servers)) # For each server url we install content for thread_index, server_url in enumerate(servers): client = demisto_client.configure(base_url=server_url, username=username, password=password, verify_ssl=False) t = Thread(target=update_content_on_demisto_instance, kwargs={'client': client, 'server': server_url, 'ami_name': ami_env, 'prints_manager': threads_prints_manager, 'thread_index': thread_index}) threads_list.append(t) run_threads_list(threads_list) # configure instances for new integrations new_integration_module_instances = [] for integration in brand_new_integrations: placeholders_map = {'%%SERVER_HOST%%': servers[0]} new_integration_module_instance = configure_integration_instance(integration, testing_client, prints_manager, placeholders_map) if new_integration_module_instance: new_integration_module_instances.append(new_integration_module_instance) all_module_instances.extend(new_integration_module_instances) # After content upload has completed - test ("Test" button) integration instances # Test all module instances (of pre-existing AND new integrations) post-updating content if all_module_instances: # only print start message if there are instances to configure prints_manager.add_print_job('Start of Instance Testing ("Test" button) after the Content Update:', print_warning, 0) else: prints_manager.add_print_job('No integrations to configure for the chosen tests. (Post-update)', print_warning, 0) prints_manager.execute_thread_prints(0) for instance in all_module_instances: integration_of_instance = instance.get('brand', '') instance_name = instance.get('name', '') msg = 'Testing ("Test" button) for instance "{}" of integration "{}" .'.format(instance_name, integration_of_instance) prints_manager.add_print_job(msg, print_color, 0, LOG_COLORS.GREEN) prints_manager.execute_thread_prints(0) # If there is a failure, __test_integration_instance will print it success, _ = __test_integration_instance(testing_client, instance, prints_manager) prints_manager.execute_thread_prints(0) if not success: postupdate_fails.add((instance_name, integration_of_instance)) else: postupdate_success.add((instance_name, integration_of_instance)) # reinitialize all clients since their authorization has probably expired by now for server_url in servers: client = demisto_client.configure(base_url=server_url, username=username, password=password, verify_ssl=False) __disable_integrations_instances(client, all_module_instances, prints_manager) prints_manager.execute_thread_prints(0) success = report_tests_status(preupdate_fails, postupdate_fails, preupdate_success, postupdate_success, new_integrations_names, prints_manager) prints_manager.execute_thread_prints(0) if not success or not installed_content_packs_successfully: sys.exit(2)
def run_private_test_scenario(tests_settings: SettingsTester, t: dict, default_test_timeout: int, skipped_tests_conf: set, nightly_integrations: list, skipped_integrations_conf: set, skipped_integration: set, filtered_tests: list, skipped_tests: set, secret_params: dict, failed_playbooks: list, playbook_skipped_integration: set, succeed_playbooks: list, slack: str, circle_ci: str, build_number: str, server: str, build_name: str, server_numeric_version: str, demisto_user: str, demisto_pass: str, demisto_api_key: str, prints_manager: ParallelPrintsManager, thread_index: int = 0): """ Checks to see if test should run given the scenario. If the test should run, it will collect the integrations which are required to run the test. :param tests_settings: SettingsTester object which contains the test variables :param t: Options being passed to the test. PID, Docker Threshold, Timeout, etc. :param default_test_timeout: Time in seconds indicating when the test should timeout if no status is reported. :param skipped_tests_conf: Collection of the tests which are skipped. :param nightly_integrations: List of integrations which should only be tested on a nightly build. :param skipped_integrations_conf: Collection of integrations which are skiped. :param skipped_integration: Set of skipped integrations. Currently not used in private. :param filtered_tests: List of tests excluded from testing. :param skipped_tests: List of skipped tests. :param secret_params: Parameters found in the content-test-conf. Used to configure the instance. :param failed_playbooks: List of failed playbooks, additional failed playbooks will be added if they failed. :param playbook_skipped_integration: Not used. :param succeed_playbooks: List of playbooks which have passed tests. :param slack: Slack client used for notifications. :param circle_ci: CircleCI token. Used to get name of dev who triggered the build. :param build_number: The build number of the CI run. Used in slack message. :param server: The FQDN of the server tests are being ran on. :param build_name: Name of the build. (Nightly, etc.) :param server_numeric_version: Version of XSOAR currently installed on the server. :param demisto_user: Username of the demisto user running the tests. :param demisto_pass: Password of the demisto user running the tests. :param demisto_api_key: API key for the demisto instance. :param prints_manager: PrintsManager object used in reporting. Will be deprecated. :param thread_index: Integer indicating what thread the test is running on. :return: """ playbook_id = t['playbookID'] integrations_conf = t.get('integrations', []) instance_names_conf = t.get('instance_names', []) test_message = 'playbook: ' + playbook_id test_options = { 'timeout': t.get('timeout', default_test_timeout), 'memory_threshold': t.get('memory_threshold', Docker.DEFAULT_CONTAINER_MEMORY_USAGE), 'pid_threshold': t.get('pid_threshold', Docker.DEFAULT_CONTAINER_PIDS_USAGE) } if not isinstance(integrations_conf, list): integrations_conf = [ integrations_conf, ] if not isinstance(instance_names_conf, list): instance_names_conf = [ instance_names_conf, ] test_skipped_integration, integrations, is_nightly_integration = collect_integrations( integrations_conf, skipped_integration, skipped_integrations_conf, nightly_integrations) if playbook_id in filtered_tests: playbook_skipped_integration.update(test_skipped_integration) # Skip tests that are missing from filtered list if filtered_tests and playbook_id not in filtered_tests: return # Skip bad test if playbook_id in skipped_tests_conf: skipped_tests.add( f'{playbook_id} - reason: {skipped_tests_conf[playbook_id]}') return # Skip integration if test_skipped_integration: return # Skip version mismatch test test_from_version = t.get('fromversion', '0.0.0') test_to_version = t.get('toversion', '99.99.99') if not (LooseVersion(test_from_version) <= LooseVersion(server_numeric_version) <= LooseVersion(test_to_version)): prints_manager.add_print_job( f'\n------ Test {test_message} start ------', print, thread_index, include_timestamp=True) warning_message = 'Test {} ignored due to version mismatch (test versions: {}-{})'.format( test_message, test_from_version, test_to_version) prints_manager.add_print_job(warning_message, print_warning, thread_index) prints_manager.add_print_job( f'------ Test {test_message} end ------\n', print, thread_index, include_timestamp=True) return placeholders_map = {'%%SERVER_HOST%%': server} are_params_set = set_integration_params(demisto_api_key, integrations, secret_params, instance_names_conf, playbook_id, prints_manager, placeholders_map, thread_index=thread_index) if not are_params_set: failed_playbooks.append(playbook_id) return test_message = update_test_msg(integrations, test_message) run_test(tests_settings, demisto_user, demisto_pass, failed_playbooks, integrations, playbook_id, succeed_playbooks, test_message, test_options, slack, circle_ci, build_number, server, build_name, prints_manager, thread_index=thread_index)
def main(): options = options_handler() username = options.user password = options.password ami_env = options.ami_env git_sha1 = options.git_sha1 servers = determine_servers_urls(ami_env) conf_path = options.conf secret_conf_path = options.secret prints_manager = ParallelPrintsManager(1) server_numeric_version = get_server_numeric_version(ami_env) conf, secret_conf = load_conf_files(conf_path, secret_conf_path) secret_params = secret_conf.get('integrations', []) if secret_conf else [] username = secret_conf.get('username') if not username else username password = secret_conf.get('userPassword') if not password else password clients = [] for server_url in servers: client = demisto_client.configure(base_url=server_url, username=username, password=password, verify_ssl=False) clients.append(client) testing_client = clients[0] tests = conf['tests'] skipped_integrations_conf = conf['skipped_integrations'] all_module_instances = [] filtered_tests, filter_configured, run_all_tests = extract_filtered_tests( is_nightly=False) tests_for_iteration = tests if run_all_tests: # Use all tests for testing, leave 'tests_for_iteration' as is pass elif filter_configured and filtered_tests: tests_for_iteration = [ test for test in tests if test.get('playbookID', '') in filtered_tests ] tests_for_iteration = filter_tests_with_incompatible_version( tests_for_iteration, server_numeric_version, prints_manager) # get a list of brand new integrations that way we filter them out to only configure instances # after updating content new_integrations_names, modified_integrations_names = get_new_and_modified_integrations( git_sha1) if new_integrations_names: print_warning('New Integrations Since Last Release:\n{}\n'.format( '\n'.join(new_integrations_names))) if modified_integrations_names: print_warning('Updated Integrations Since Last Release:\n{}\n'.format( '\n'.join(modified_integrations_names))) # Each test is a dictionary from Tests/conf.json which may contain the following fields # "playbookID", "integrations", "instance_names", "timeout", "nightly", "fromversion", "toversion" # Note that only the "playbookID" field is required with all of the others being optional. # Most tests have an "integrations" field listing the integration used for that playbook # and sometimes an "instance_names" field which is used when there are multiple instances # of an integration that we want to configure with different configuration values. Look at # [conf.json](../conf.json) for examples brand_new_integrations = [] for test in tests_for_iteration: integrations = get_integrations_for_test(test, skipped_integrations_conf) instance_names_conf = test.get('instance_names', []) if not isinstance(instance_names_conf, list): instance_names_conf = [instance_names_conf] integrations_names = [i.get('name') for i in integrations] print_warning('All Integrations for test "{}":'.format( test.get('playbookID'))) print_warning(integrations_names) new_integrations, modified_integrations, unchanged_integrations, integration_to_status = group_integrations( integrations, skipped_integrations_conf, new_integrations_names, modified_integrations_names) integrations_msg = '\n'.join([ '"{}" - {}'.format(key, val) for key, val in integration_to_status.items() ]) print_warning('{}\n'.format(integrations_msg)) integrations_to_configure = modified_integrations[:] integrations_to_configure.extend(unchanged_integrations) # set params for new integrations and [modified + unchanged] integrations, then add the new ones # to brand_new_integrations list for later use new_ints_params_set = set_integration_params(new_integrations, secret_params, instance_names_conf) ints_to_configure_params_set = set_integration_params( integrations_to_configure, secret_params, instance_names_conf) if not new_ints_params_set: print_error( 'failed setting parameters for integrations "{}"'.format( '\n'.join(new_integrations))) if not ints_to_configure_params_set: print_error( 'failed setting parameters for integrations "{}"'.format( '\n'.join(integrations_to_configure))) if not (new_ints_params_set and ints_to_configure_params_set): continue brand_new_integrations.extend(new_integrations) module_instances = [] for integration in integrations_to_configure: module_instances.append( configure_integration_instance(integration, testing_client, prints_manager)) all_module_instances.extend(module_instances) preupdate_fails = set() postupdate_fails = set() # Test all module instances (of modified + unchanged integrations) pre-updating content if all_module_instances: # only print start message if there are instances to configure print_warning( 'Start of Instance Testing ("Test" button) prior to Content Update:' ) else: print_warning( 'No integrations to configure for the chosen tests. (Pre-update)') for instance in all_module_instances: integration_of_instance = instance.get('brand', '') instance_name = instance.get('name', '') msg = 'Testing ("Test" button) for instance "{}" of integration "{}".'.format( instance_name, integration_of_instance) print(msg) # If there is a failure, __test_integration_instance will print it success = __test_integration_instance(testing_client, instance, prints_manager) prints_manager.execute_thread_prints(0) if not success: preupdate_fails.add((instance_name, integration_of_instance)) threads_list = [] threads_prints_manager = ParallelPrintsManager(len(clients)) # For each server url we install content for thread_index, (client, server_url) in enumerate(zip(clients, servers)): t = Thread(target=update_content_on_demisto_instance, kwargs={ 'client': client, 'server': server_url, 'prints_manager': threads_prints_manager, 'thread_index': thread_index }) threads_list.append(t) run_threads_list(threads_list) # configure instances for new integrations new_integration_module_instances = [] for integration in brand_new_integrations: new_integration_module_instances.append( configure_integration_instance(integration, testing_client, prints_manager)) all_module_instances.extend(new_integration_module_instances) # After content upload has completed - test ("Test" button) integration instances # Test all module instances (of pre-existing AND new integrations) post-updating content if all_module_instances: print_warning( 'Start of Instance Testing ("Test" button) after the Content Update:' ) else: print_warning( 'No integrations to configure for the chosen tests. (Post-update)') for instance in all_module_instances: integration_of_instance = instance.get('brand', '') instance_name = instance.get('name', '') msg = 'Testing ("Test" button) for instance "{}" of integration "{}" .'.format( instance_name, integration_of_instance) print(msg) # If there is a failure, __test_integration_instance will print it success = __test_integration_instance(testing_client, instance, prints_manager) prints_manager.execute_thread_prints(0) if not success: postupdate_fails.add((instance_name, integration_of_instance)) # reinitialize all clients since their authorization has probably expired by now for server_url in servers: client = demisto_client.configure(base_url=server_url, username=username, password=password, verify_ssl=False) __disable_integrations_instances(client, all_module_instances, prints_manager) prints_manager.execute_thread_prints(0) success = report_tests_status(preupdate_fails, postupdate_fails, new_integrations_names) if not success: sys.exit(1)
def search_pack(client: demisto_client, prints_manager: ParallelPrintsManager, pack_display_name: str, pack_id: str, thread_index: int, lock: Lock) -> dict: """ Make a pack search request. Args: client (demisto_client): The configured client to use. prints_manager (ParallelPrintsManager): Print manager object. pack_display_name (string): The pack display name. pack_id (string): The pack ID. thread_index (int): the thread index. lock (Lock): A lock object. Returns: (dict): Returns the pack data if found, or empty dict otherwise. """ try: # make the search request response_data, status_code, _ = demisto_client.generic_request_func( client, path=f'/contentpacks/marketplace/{pack_id}', method='GET', accept='application/json', _request_timeout=None) if 200 <= status_code < 300: result_object = ast.literal_eval(response_data) if result_object and result_object.get('currentVersion'): print_msg = f'Found pack "{pack_display_name}" by its ID "{pack_id}" in bucket!\n' prints_manager.add_print_job(print_msg, print_color, thread_index, LOG_COLORS.GREEN) prints_manager.execute_thread_prints(thread_index) pack_data = { 'id': result_object.get('id'), 'version': result_object.get('currentVersion') } return pack_data else: print_msg = f'Did not find pack "{pack_display_name}" by its ID "{pack_id}" in bucket.\n' prints_manager.add_print_job(print_msg, print_color, thread_index, LOG_COLORS.RED) prints_manager.execute_thread_prints(thread_index) raise Exception(print_msg) else: result_object = ast.literal_eval(response_data) msg = result_object.get('message', '') err_msg = f'Search request for pack "{pack_display_name}" with ID "{pack_id}", failed with status code ' \ f'{status_code}\n{msg}' raise Exception(err_msg) except Exception as e: err_msg = f'Search request for pack "{pack_display_name}" with ID "{pack_id}", failed. Reason:\n{str(e)}' prints_manager.add_print_job(err_msg, print_color, thread_index, LOG_COLORS.RED) lock.acquire() global SUCCESS_FLAG SUCCESS_FLAG = False lock.release()
def install_nightly_packs(client: demisto_client, host: str, prints_manager: ParallelPrintsManager, thread_index: int, packs_to_install: List, request_timeout: int = 999999): """ Install content packs on nightly build. We will catch the exception if pack fails to install and send the request to install packs again without the corrupted pack. Args: client(demisto_client): The configured client to use. host (str): The server URL. prints_manager (ParallelPrintsManager): Print manager object. thread_index (int): the thread index. packs_to_install (list): A list of the packs to install. request_timeout (int): Timeout settings for the installation request. Returns: None: No data returned. """ packs_to_install_str = ', '.join([pack['id'] for pack in packs_to_install]) message = 'Installing the following packs in server {}:\n{}'.format( host, packs_to_install_str) prints_manager.add_print_job(message, print_color, thread_index, LOG_COLORS.GREEN, include_timestamp=True) prints_manager.execute_thread_prints(thread_index) # make the pack installation request all_packs_install_successfully = False request_data = {'packs': packs_to_install, 'ignoreWarnings': True} while not all_packs_install_successfully: try: response_data, status_code, _ = demisto_client.generic_request_func( client, path='/contentpacks/marketplace/install', method='POST', body=request_data, accept='application/json', _request_timeout=request_timeout) if 200 <= status_code < 300: packs_data = [{ 'ID': pack.get('id'), 'CurrentVersion': pack.get('currentVersion') } for pack in ast.literal_eval(response_data)] packs_message = f'The following packs were successfully installed:\n{packs_data}' prints_manager.add_print_job(packs_message, print_color, thread_index, LOG_COLORS.GREEN, include_timestamp=True) else: result_object = ast.literal_eval(response_data) message = result_object.get('message', '') err_msg = f'Failed to install packs - with status code {status_code}\n{message}\n' prints_manager.add_print_job(err_msg, print_error, thread_index, include_timestamp=True) raise Exception(err_msg) break except Exception as e: err_msg = f'The request to install packs has failed. Reason:\n{str(e)}\n' prints_manager.add_print_job(err_msg, print_error, thread_index, include_timestamp=True) all_packs_install_successfully = False malformed_pack_id = find_malformed_pack_id(str(e)) if not malformed_pack_id: break # Remove the malformed pack from the pack to install list. packs = [ pack for pack in packs_to_install if pack['id'] not in malformed_pack_id ] request_data = {'packs': packs, 'ignoreWarnings': True} finally: prints_manager.execute_thread_prints(thread_index)
def install_packs(client: demisto_client, host: str, prints_manager: ParallelPrintsManager, thread_index: int, packs_to_install: list, request_timeout: int = 999999, is_nightly: bool = False): """ Make a packs installation request. Args: client (demisto_client): The configured client to use. host (str): The server URL. prints_manager (ParallelPrintsManager): Print manager object. thread_index (int): the thread index. packs_to_install (list): A list of the packs to install. request_timeout (int): Timeout settings for the installation request. is_nightly (bool): Is the build nightly or not. """ if is_nightly: install_nightly_packs(client, host, prints_manager, thread_index, packs_to_install) request_data = {'packs': packs_to_install, 'ignoreWarnings': True} packs_to_install_str = ', '.join([pack['id'] for pack in packs_to_install]) message = 'Installing the following packs in server {}:\n{}'.format( host, packs_to_install_str) prints_manager.add_print_job(message, print_color, thread_index, LOG_COLORS.GREEN, include_timestamp=True) prints_manager.execute_thread_prints(thread_index) # make the pack installation request try: response_data, status_code, _ = demisto_client.generic_request_func( client, path='/contentpacks/marketplace/install', method='POST', body=request_data, accept='application/json', _request_timeout=request_timeout) if 200 <= status_code < 300: packs_data = [{ 'ID': pack.get('id'), 'CurrentVersion': pack.get('currentVersion') } for pack in ast.literal_eval(response_data)] packs_message = f'The following packs were successfully installed:\n{packs_data}' prints_manager.add_print_job(packs_message, print_color, thread_index, LOG_COLORS.GREEN, include_timestamp=True) else: result_object = ast.literal_eval(response_data) message = result_object.get('message', '') err_msg = f'Failed to install packs - with status code {status_code}\n{message}\n' prints_manager.add_print_job(err_msg, print_error, thread_index, include_timestamp=True) raise Exception(err_msg) except Exception as e: err_msg = f'The request to install packs has failed. Reason:\n{str(e)}\n' prints_manager.add_print_job(err_msg, print_error, thread_index, include_timestamp=True) global SUCCESS_FLAG SUCCESS_FLAG = False finally: prints_manager.execute_thread_prints(thread_index)